diff --git a/Build/Changes.txt b/Build/Changes.txt index acdf799d7..67b0e91d8 100644 --- a/Build/Changes.txt +++ b/Build/Changes.txt @@ -2,7 +2,7 @@ = = = Notepad3 - light-weight Scintilla-based text editor for Windows = = = -= (c) Rizonesoft 2008-2022 = += (c) Rizonesoft 2008-2023 = = https://www.rizonesoft.com = = = ================================================================================ @@ -34,7 +34,7 @@ UCD - (UCD)ARDET is an Encoding Detector Library ======================================================== -Current BETA/RC Version 5.22.1228.(build_#) (2022-12-28) +Current BETA/RC Version 5.23.101.(build_#) (2023-01-01) ======================================================== -------------------------------------------------------- @@ -63,6 +63,12 @@ NEW: CHANGES: -------------------------------------------------------- [.###.#]- . +[.101.1]- Fix and refactoring window positioning respecting monitor DPI. +[1230.1]- Revert to Lexilla's standard Markdown lexer (LEX). +[1230.1]- Change background color for Heading 1 to enhance contrast to std Hyperlink (LEX). +[1230.1]- Visible representation of EOL characters. +[1230.1]- Refactoring of using SCI_REPLACETARGET(MINIMAL). +[1230.1]- Lexer Registry-Files: split string and GUID String coloring (LEX). [1228.1]- JSON lexer: Same style for SCE_JSON_COMPACTIRI and SCE_JSON_PROPERTYNAME (LEX). [1228.1]- Status-bar double-click line-break mode: Cycle only between CR+LF <-> LF modes. [1220.1]- Update Lexer "AutoIt3 Script" to Autoit v3.3.16.1. @@ -111,6 +117,8 @@ CHANGES Versions in Tools or Libraries: FIXES: -------------------------------------------------------- [.###.#]- . +[1230.1]- Minor bugs related to new feature Change-History. +[1230.1]- (re)setting default window position in case of non std DPI resolution. [1228.1]- Speedup search&replace in large text files. [1227.1]- Use alternate path, if Path_GetKnownFolder() failed. [1215.1]- Set alpha (80) for "highlight current line" translucency, if not given. diff --git a/Build/Docs/KeyboardShortcuts.txt b/Build/Docs/KeyboardShortcuts.txt index 9c9fb4d29..8f650554e 100644 --- a/Build/Docs/KeyboardShortcuts.txt +++ b/Build/Docs/KeyboardShortcuts.txt @@ -2,7 +2,7 @@ = = = Notepad3 - light-weight Scintilla-based text editor for Windows = = = -= (c) Rizonesoft 2008-2022 = += (c) Rizonesoft 2008-2023 = = https://www.rizonesoft.com = = = ================================================================================ diff --git a/Build/Docs/Notepad3.txt b/Build/Docs/Notepad3.txt index 95ff685ad..fd1078d4b 100644 --- a/Build/Docs/Notepad3.txt +++ b/Build/Docs/Notepad3.txt @@ -3,7 +3,7 @@ = = = Notepad3 - light-weight Scintilla-based text editor for Windows = = = -= (c) Rizonesoft 2008-2022 = += (c) Rizonesoft 2008-2023 = = https://rizonesoft.com = = = = forked from Notepad2-mod = diff --git a/Build/make_portable(.zip).cmd b/Build/make_portable(.zip).cmd index da0645380..acc254ee5 100644 --- a/Build/make_portable(.zip).cmd +++ b/Build/make_portable(.zip).cmd @@ -12,7 +12,7 @@ rem * Batch file for creating "Portable (*.zip)" packages rem * * rem * See License.txt for details about distribution and modification. * rem * * -rem * (c) Rizonesoft 2008-2022 * +rem * (c) Rizonesoft 2008-2023 * rem * https://rizonesoft.com * rem * * rem ****************************************************************************** diff --git a/Build/notepad3_x64_setup.iss b/Build/notepad3_x64_setup.iss index e8e22e9bd..a9ec6f8dc 100644 --- a/Build/notepad3_x64_setup.iss +++ b/Build/notepad3_x64_setup.iss @@ -1,6 +1,6 @@ ;* Notepad3 - Installer script x64 and amr64 ;* -;* (c) Rizonesoft 2008-2022 +;* (c) Rizonesoft 2008-2023 ; Requirements: ; Inno Setup: https://www.jrsoftware.org/isdl.php @@ -27,7 +27,7 @@ #define app_name "Notepad3" #define app_publisher "Rizonesoft" #define app_version GetVersionNumbersString(bindir + "\Release_x64_v143\Notepad3.exe") -#define app_copyright "Copyright © 2008-2022 Rizonesoft" +#define app_copyright "Copyright © 2008-2023 Rizonesoft" #define quick_launch "{userappdata}\Microsoft\Internet Explorer\Quick Launch" [Setup] diff --git a/Build/notepad3_x86_setup.iss b/Build/notepad3_x86_setup.iss index 99bff0ce8..57c23f0cf 100644 --- a/Build/notepad3_x86_setup.iss +++ b/Build/notepad3_x86_setup.iss @@ -1,6 +1,6 @@ ;* Notepad3 - Installer script x86 ;* -;* (c) Rizonesoft 2008-2022 +;* (c) Rizonesoft 2008-2023 ; Requirements: ; Inno Setup: https://www.jrsoftware.org/isdl.php @@ -27,7 +27,7 @@ #define app_name "Notepad3" #define app_publisher "Rizonesoft" #define app_version GetVersionNumbersString(bindir + "\Release_x86_v143\Notepad3.exe") -#define app_copyright "Copyright © 2008-2022 Rizonesoft" +#define app_copyright "Copyright © 2008-2023 Rizonesoft" #define quick_launch "{userappdata}\Microsoft\Internet Explorer\Quick Launch" [Setup] diff --git a/License.txt b/License.txt index 70e6a663b..0ea27e0fc 100644 --- a/License.txt +++ b/License.txt @@ -1,6 +1,6 @@ License for Notepad3 and MiniPath. ===================== -Notepad3 and MiniPath Copyright (c) 2008-2022 Rizonesoft, All rights reserved. +Notepad3 and MiniPath Copyright (c) 2008-2023 Rizonesoft, All rights reserved. https://www.rizonesoft.com Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/Readme.txt b/Readme.txt index 30e127d59..4b461ea95 100644 --- a/Readme.txt +++ b/Readme.txt @@ -2,7 +2,7 @@ = = = Notepad3 - light-weight Scintilla-based text editor for Windows = = = -= (c) Rizonesoft 2008-2022 = += (c) Rizonesoft 2008-2023 = = https://www.rizonesoft.com = = = ================================================================================ @@ -148,7 +148,7 @@ Notepad3 icon by Vexels.com https://www.vexels.com -------------------------------------------------------------------------------- Notepad3 Licence: ----------------- -Notepad3 and MiniPath Copyright © 2008-2022 Rizonesoft, All rights reserved. +Notepad3 and MiniPath Copyright © 2008-2023 Rizonesoft, All rights reserved. https://www.rizonesoft.com Redistribution and use in source and binary forms, with or without modification, diff --git a/Versions/AssemblyInfo.inf b/Versions/AssemblyInfo.inf index 7eef75829..ff474fb99 100644 --- a/Versions/AssemblyInfo.inf +++ b/Versions/AssemblyInfo.inf @@ -7,7 +7,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Rizonesoft")] [assembly: AssemblyProduct("Notepad3")] -[assembly: AssemblyCopyright("Copyright © Rizonesoft 2008-2022")] +[assembly: AssemblyCopyright("Copyright © Rizonesoft 2008-2023")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Versions/day.txt b/Versions/day.txt index fe1b06087..398050c62 100644 --- a/Versions/day.txt +++ b/Versions/day.txt @@ -1 +1 @@ -1228 +101 diff --git a/language/Line numbers to translate.txt b/language/Line numbers to translate.txt index 42864bd4d..25c9b2008 100644 --- a/language/Line numbers to translate.txt +++ b/language/Line numbers to translate.txt @@ -3,7 +3,7 @@ == This ".txt" file is intended for "Translators" to communicate to them the "Line numbers" of the == == "Added or Modified" items in the "Resource" files ("filename_xx_yy.rc" and "grepWinNP3.lang"). == == == -== Last update: 2022-12-13 == +== Last update: 2022-12-30 == ======================================================================================================== January 2022: Line numbers to translate_2022-01 - https://workupload.com/file/3kmZN49gB9w (2022-01-29) @@ -28,7 +28,7 @@ October 2022: Line numbers to translate_2022-10 - https://workupload.com/file/ November 2022: Line numbers to translate_2022-11 - No "Added or Modified" items in November 2022 -December 2022: Line numbers to translate_2022-12 - https://workupload.com/file/Yd53Fd54Kzg (2022-12-13) +December 2022: Line numbers to translate_2022-12 - https://workupload.com/file/Jqk5WuVHdRP (2022-12-30) Comments and suggestions are welcome... 😃 diff --git a/language/common_res.rc b/language/common_res.rc index f09f454a4..1decccb0c 100644 --- a/language/common_res.rc +++ b/language/common_res.rc @@ -71,7 +71,7 @@ IDC_COPY CURSOR "Copy.cur" // ============================================================================= // Following Text is streamed to RichEdit Control supporting ANSI CP-1252 only // Unicode characters have to be encoded using '\\uN' sequences. -// Example: Kng => K\\u252nng +// Example: K�ng => K\\u252nng // ============================================================================= STRINGTABLE @@ -175,7 +175,7 @@ IDS_MUI_ABOUT_LICENSES "\ IDS_MUI_ABOUT_RTF_6 "\ \\cf0 \\fs20\\b1\\ul1 Notepad3 License:\\ul0\\b0\\fs18\\par\ \\cf0 \\par\ -\\cf0 Notepad3 and MiniPath Copyright \\u0169 2008-2022 Rizonesoft, All rights reserved.\\par\ +\\cf0 Notepad3 and MiniPath Copyright \\u0169 2008-2023 Rizonesoft, All rights reserved.\\par\ \\cf0 https://www.rizonesoft.com\\par\ \\cf0 \\par\ \\cf0 Redistribution and use in source and binary forms, with or without modification,\\par\ diff --git a/language/np3_af_za/dialogs_af_za.rc b/language/np3_af_za/dialogs_af_za.rc index ec9e06405..82eca6753 100644 --- a/language/np3_af_za/dialogs_af_za.rc +++ b/language/np3_af_za/dialogs_af_za.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 310, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Command Line Help" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,249,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,288,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 283, 142 diff --git a/language/np3_af_za/lexer_af_za.rc b/language/np3_af_za/lexer_af_za.rc index 0575fd8ac..b27e8a9bd 100644 --- a/language/np3_af_za/lexer_af_za.rc +++ b/language/np3_af_za/lexer_af_za.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Simbool Operateur" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_af_za/strings_af_za.rc b/language/np3_af_za/strings_af_za.rc index 5ee3adfe6..537591fdc 100644 --- a/language/np3_af_za/strings_af_za.rc +++ b/language/np3_af_za/strings_af_za.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s voorkoms(e) van gespesifiseerde soekpatroon vervang." IDS_MUI_ASK_ENCODING "As u die lêer kodering van een kodering na 'n ander skuif, kan u nie-ondersteunde teks vervang met verstek karakters, en die ongedaan geskiedenis sal skoongemaak word. Gaan aan?" IDS_MUI_ASK_ENCODING2 "Jy is op die punt om die kodering van 'n leë lêer te verander. Let daarop dat dit die geskiedenis ongedaan maak, aangesien dit nie met die nuwe enkodering gesinkroniseer kan word nie. Gaan aan?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" is beskermd. Stoor na 'n ander lêer?" IDS_MUI_FILECHANGENOTIFY "Die huidige lêer is gewysig deur 'n eksterne program. Herlaai?" @@ -315,8 +316,8 @@ Opsies:\r\n\ /b\tMaak 'n nuwe plakbord oop om klipbordinskrywings te versamel.\r\n\ /n\tMaak altyd 'n nuwe venster oop (/ns enkele lêer instansie).\r\n\ /r\tHergebruik venster (/rs enkele lêer instansie).\r\n\ -/p\tStel venster posisie en grootte (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tor /p ,,,[,,] [alle heelgetalle].\r\n\ +/p\tStel venster posisie en grootte (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tor /p ,,,[,,] [alle heelgetalle].\r\n\ /t\tStel venster titel.\r\n\ /i\tBegin as tray ikoon.\r\n\ /o\tHou venster bo-op.\r\n\ diff --git a/language/np3_be_by/dialogs_be_by.rc b/language/np3_be_by/dialogs_be_by.rc index f65b4a66f..b1b60ee6b 100644 --- a/language/np3_be_by/dialogs_be_by.rc +++ b/language/np3_be_by/dialogs_be_by.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 320, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Параметры камандавага радку" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,259,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,298,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 313, 142 diff --git a/language/np3_be_by/lexer_be_by.rc b/language/np3_be_by/lexer_be_by.rc index b92904d2b..bad51da1f 100644 --- a/language/np3_be_by/lexer_be_by.rc +++ b/language/np3_be_by/lexer_be_by.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_be_by/strings_be_by.rc b/language/np3_be_by/strings_be_by.rc index a4f271288..56d68f448 100644 --- a/language/np3_be_by/strings_be_by.rc +++ b/language/np3_be_by/strings_be_by.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "Заменена ўваходжанняў вызначанага шаблона пошуку: %s." IDS_MUI_ASK_ENCODING "Пераключэнне кадоўкі файла з адной на другую можа замяніць непадтрымоўваны тэкст сімваламі-заменнікамі, а гісторыя адмены будзе прыбрана. Усё роўна працягнуць?" IDS_MUI_ASK_ENCODING2 "Вы збіраецеся змяніць кадоўку пустога файла. Звярніце ўвагу, што гэта прыбярэ гісторыю адмены, паколькі яна не можа быць скаардынаванай з новай кадоўкай. Усё роўна працягнуць?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE "«%s» толькі для чытання. Захваць у іншы файл?" IDS_MUI_FILECHANGENOTIFY "Гэты файл быў зменены вонкавай праграмай. Пераадкрыць яго?" @@ -295,7 +296,7 @@ IDS_MUI_CMDLINEHELP "\ Notepad3 [/?] [...[Кадоўка]] [...[Канчаткі радкоў]] [/e] [/g] [/m] [/l]\r\n\ \t[/q] [/s] [/d] [/h] [/x] [/c] [/b] [/n] [/r| [/p] [/t] [/i] [/o]\r\n\ \t[/f] [/u] [/v] [/vd] [/y] [/z] [[дыск:][шлях]імя[...]]\r\n\r\n\ -файл\tПавінен быць апошнім аргументам, першапачаткова\r\n\tбез прабелаў.\r\n\ +файл\tПавінен быць апошнім аргументам, першапачаткова без прабелаў.\r\n\ +\tНекалькі аргументаў файлаў (з кадаванымі прабеламі).\r\n\ -\tАдзін аргумент файла (без кадаваных прабелаў).\r\n\r\n\ Параметры:\r\n\ @@ -304,7 +305,7 @@ Notepad3 [/?] [...[Кадоўка]] [...[Канчаткі радкоў]] [/e] [/ ...\tФармат канчаткаў радкоў (/crlf, /cr, /lf).\r\n\ /e\tЗыходная кадоўка файла.\r\n\ /g\tПерайсці да зазначанага месца (/g -1 канец файла).\r\n\ -/m\tЗнайсці названы тэкст (/m- апошні, /mr regex,\r\n\t/mb адваротная косая рыска).\r\n\ +/m\tЗнайсці названы тэкст (/m- апошні, /mr regex, /mb адваротная \r\n\tкосая рыска).\r\n\ /l\tАўтаабнаўленне змененых файлаў.\r\n\ /q\tПрымусіць ствараць новыя файлы без запыту.\r\n\ /s\tВыбраць схему сінтаксісу.\r\n\ @@ -315,8 +316,8 @@ Notepad3 [/?] [...[Кадоўка]] [...[Канчаткі радкоў]] [/e] [/ /b\tАдкрыць новае акно для збірання змяненняў буфера абмену.\r\n\ /n\tЗаўсёды адкрываць новае акно (/ns адзін экзэмпляр файла).\r\n\ /r\tВыкарыстаць былое акно (/rs адзін экзэмпляр файла).\r\n\ -/p\tЗадаць пазіцыю і памер акна (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tці /p ,,,[,,] [цэлыя лікі].\r\n\ +/p\tЗадаць пазіцыю і памер акна (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tці /p ,,,[,,] [цэлыя лікі].\r\n\ /t\tЗадаць назву акна.\r\n\ /i\tЗапусціць значком на паліцы задач.\r\n\ /o\tЗверху іншых вокнаў.\r\n\ @@ -325,7 +326,7 @@ Notepad3 [/?] [...[Кадоўка]] [...[Канчаткі радкоў]] [/e] [/ /v\tНадрукаваць файл адразу і выйсці.\r\n\ /vd\tНадрукаваць файл (адкрыць дыялог друку).\r\n\ /y\tШукаць у пераменнай PATH калі выкарыстаны адносны шлях.\r\n\ -/z\tПрапусціць наступны (прыдатна для пошуку з рэгулярным\r\n\tвыразам).\r\n\r\n\ +/z\tПрапусціць наступны (прыдатна для пошуку з рэгулярным выразам).\r\n\r\n\ Прыклады:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ \t... Новы файл: ""Test.txt"" Кадоўка=UTF-8-BOM, Канчаткі=CRLF.\r\n\ diff --git a/language/np3_de_de/dialogs_de_de.rc b/language/np3_de_de/dialogs_de_de.rc index a39499a47..57bcabf07 100644 --- a/language/np3_de_de/dialogs_de_de.rc +++ b/language/np3_de_de/dialogs_de_de.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 320, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Kommandozeilen Hilfe" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,259,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,298,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_de_de/strings_de_de.rc b/language/np3_de_de/strings_de_de.rc index e9fb66d9d..3f68cb218 100644 --- a/language/np3_de_de/strings_de_de.rc +++ b/language/np3_de_de/strings_de_de.rc @@ -296,7 +296,7 @@ Nutzung:\r\n\ Notepad3 [/?] [...[Codierung]] [...[Zeilenumbruch Modus]] [/e] [/g] [/m] [/l]\r\n\ \t[/q] [/s] [/d] [/h] [/x] [/c] [/b] [/n] [/r| [/p] [/t] [/i] [/o]\r\n\ \t[/f] [/u] [/v] [/vd] [/y] [/z] [[Laufwerk:][Pfad]Datei[...]]\r\n\r\n\ -Datei\tMuss das letzte Argument sein, normalerweise\r\n\tkeine gequoteten Leerstellen.\r\n\ +Datei\tMuss das letzte Argument sein, normalerweise keine gequoteten Leerstellen.\r\n\ +\tAkzeptiere mehrere Dateien (mit gequoteten Leerstellen).\r\n\ -\tAkzeptiere ein einzelne Datei (ohne gequotete Leerstellen).\r\n\r\n\ Optionen:\r\n\ @@ -305,19 +305,19 @@ Optionen:\r\n\ ...\tZeilenumbruch Modus (/crlf, /cr, /lf).\r\n\ /e\tDatei Quellen Codierung.\r\n\ /g\tSpringe zur gegebenen Position (/g -1 Ende der Datei).\r\n\ -/m\tFinde gegebenen Suchbegriff (/m- letzter, /mr regex,\r\n\t/mb backslash).\r\n\ +/m\tFinde gegebenen Suchbegriff (/m- letzter, /mr regex, /mb backslash).\r\n\ /l\tAuto-Neu-Laden einer veränderten Datei.\r\n\ /q\tErzwinge die Erzeugung einer neuen Datei ohne Nachfrage.\r\n\ /s\tSetze das gegebene Syntax Schema.\r\n\ /d\tSetze das Standard-Text Schema.\r\n\ /h\tSetze das Web Quellcode Schema.\r\n\ /x\tSetze das XML Dokument Schema.\r\n\ -/c\tÖffne ein neues Fenster und füge den Inhalt\r\n\tder Zwischenablage ein.\r\n\ -/b\tÖffne ein neues 'Paste Board' um die Einträge\r\n\tder Zwischenablage zu sammeln.\r\n\ +/c\tÖffne ein neues Fenster und füge den Inhalt der Zwischenablage ein.\r\n\ +/b\tÖffne ein neues 'Paste Board' um die Einträge der Zwischenablage \r\n\tzu sammeln.\r\n\ /n\tÖffne immer ein neues Fenster (/ns single file instance).\r\n\ /r\tBenutze geöffnetes Fenster erneut (/rs single file instance).\r\n\ -/p\tSetze Fenster: Position und Größe (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\toder /p ,,,[,,] [ganzzahlig].\r\n\ +/p\tSetze Fenster: Position und Größe (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\toder /p ,,,[,,] [ganzzahlig].\r\n\ /t\tSetze Fenster-Titel.\r\n\ /i\tStarte als 'Tray-Icon'.\r\n\ /o\tHalte Fenster immer auf oberster Ebene.\r\n\ @@ -326,10 +326,10 @@ Optionen:\r\n\ /v\tDrucke Datei und beende Programm.\r\n\ /vd\tDrucke Datei (öffne Drucker-Dialog).\r\n\ /y\tSuche relative Dateinamen im Umgebungs PATH.\r\n\ -/z\tÜberspringe Nächstes (nützlich für Registy-Basierte\r\n\tNotepad Ersetzung).\r\n\r\n\ +/z\tÜberspringe Nächstes (nützlich für Registy-Basierte Notepad Ersetzung).\r\n\r\n\ Beispiele:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ - \t... Eine neue Datei öffnen: ""Test.txt"" Codierung=UTF-8-BOM,\r\n\tEoL=CRLF.\r\n\ + \t... Eine neue Datei öffnen: ""Test.txt"" Codierung=UTF-8-BOM, EoL=CRLF.\r\n\ Notepad3 /v d:\\temp\\Test.txt\r\n\ \t... Drucke Datei: ""Test.txt"" direkt.\ " diff --git a/language/np3_el_gr/dialogs_el_gr.rc b/language/np3_el_gr/dialogs_el_gr.rc index 133f6c3d0..8cf165374 100644 --- a/language/np3_el_gr/dialogs_el_gr.rc +++ b/language/np3_el_gr/dialogs_el_gr.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 330, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Βοήθεια γραμμής εντολών" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "&Εντάξει",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "&Εντάξει",IDOK,269,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,308,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 283, 142 diff --git a/language/np3_el_gr/lexer_el_gr.rc b/language/np3_el_gr/lexer_el_gr.rc index 476b477a4..48c3f57cb 100644 --- a/language/np3_el_gr/lexer_el_gr.rc +++ b/language/np3_el_gr/lexer_el_gr.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_el_gr/strings_el_gr.rc b/language/np3_el_gr/strings_el_gr.rc index f5e06acab..436b03e71 100644 --- a/language/np3_el_gr/strings_el_gr.rc +++ b/language/np3_el_gr/strings_el_gr.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "Έγινε αντικατάσταση σε %s εμφάνιση(εις) του καθορισμένου μοτίβου αναζήτησης." IDS_MUI_ASK_ENCODING "Η εναλλαγή κωδικοποίησης αρχείου από μία κωδικοποίηση σε άλλη μπορεί να αντικαταστήσει το μη υποστηριζόμενο κείμενο με προεπιλεγμένους χαρακτήρες και το ιστορικό αναίρεσης θα απαλειφθεί. Συνέχεια;" IDS_MUI_ASK_ENCODING2 "Πρόκειται να αλλάξετε την κωδικοποίηση ενός κενού αρχείου. Σημειώστε ότι αυτό θα διαγράψει το ιστορικό αναίρεσης, καθώς δεν μπορεί να συγχρονιστεί με τη νέα κωδικοποίηση. Συνέχεια;" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE "Το ""%s"" είναι μόνο για ανάγνωση. Να αποθηκευτεί σε διαφορετικό αρχείο;" IDS_MUI_FILECHANGENOTIFY "Το τρέχον αρχείο έχει τροποποιηθεί από ένα εξωτερικό πρόγραμμα. Να φορτωθεί ξανά;" @@ -292,11 +293,11 @@ STRINGTABLE BEGIN IDS_MUI_CMDLINEHELP "\ Χρήση:\r\n\ -Notepad3 [/?] [...[Κωδικοποίηση]] [...[Λειτουργία κατάληξης γραμμής]]\r\n\t[/e] [/g]\r\n\ +Notepad3 [/?] [...[Κωδικοποίηση]] [...[Λειτουργία κατάληξης γραμμής]] [/e] [/g]\r\n\ \t[/m] [/l] [/q] [/s] [/d] [/h] [/x] [/c] [/b] [/n] [/r| [/p] [/t] [/i] [/o]\r\n\ \t[/f] [/u] [/v] [/vd] [/y] [/z] [[οδηγός:][διαδρομή]αρχείο[...]]\r\n\r\n\ -αρχείο\tΠρέπει να είναι το τελευταίο όρισμα, από προεπιλογή χωρίς κενά\r\n\tμέσα σε εισαγωγικά.\r\n\ -+\tΑποδοχή πολλαπλών ορισμάτων αρχείων (με κενά εντός\r\n\tεισαγωγικών).\r\n\ +αρχείο\tΠρέπει να είναι το τελευταίο όρισμα, από προεπιλογή χωρίς κενά μέσα \r\n\tσε εισαγωγικά.\r\n\ ++\tΑποδοχή πολλαπλών ορισμάτων αρχείων (με κενά εντός εισαγωγικών).\r\n\ -\tΑποδοχή ορίσματος ενός αρχείου (χωρίς κενά εντός εισαγωγικών).\r\n\r\n\ Επιλογές:\r\n\ /?\tΕμφάνιση αυτού του μηνύματος βοήθειας.\r\n\ @@ -304,19 +305,19 @@ Notepad3 [/?] [...[Κωδικοποίηση]] [...[Λειτουργία κατά ...\tΛειτουργία κατάληξης γραμμής (/crlf, /cr, /lf).\r\n\ /e\tΚωδικοποίηση του αρχείου προέλευσης.\r\n\ /g\tΜετάβαση σε καθορισμένη θέση (/g -1 τέλος του αρχείου).\r\n\ -/m\tΣυμφωνία καθορισμένου κειμένου (/m- Τελευταία,\r\n\t/mr Κανονική έκφραση, /mb Ανάστροφη κάθετος).\r\n\ +/m\tΣυμφωνία καθορισμένου κειμένου (/m- Τελευταία, /mr Κανονική έκφραση, \r\n\t/mb Ανάστροφη κάθετος).\r\n\ /l\tΑυτόματη φόρτωση μεταβληθέντων αρχείων.\r\n\ /q\tΑναγκαστική δημιουργία νέων αρχείων χωρίς ερώτηση.\r\n\ /s\tΕπιλογή καθορισμένου συνδυασμού σύνταξης.\r\n\ /d\tΕπιλογή προεπιλεγμένου συνδυασμού κειμένου.\r\n\ /h\tΕπιλογή συνδυασμού πηγαίου κώδικα Web.\r\n\ /x\tΕπιλογή συνδυασμού εγγράφων XML.\r\n\ -/c\tΆνοιγμα νέου παραθύρου και επικόλληση περιεχομένων του\r\n\tπρόχειρου.\r\n\ -/b\tΆνοιγμα νέου πίνακα επικόλλησης για τη συλλογή καταχωρήσεων\r\n\tτου πρόχειρου.\r\n\ +/c\tΆνοιγμα νέου παραθύρου και επικόλληση περιεχομένων του πρόχειρου.\r\n\ +/b\tΆνοιγμα νέου πίνακα επικόλλησης για τη συλλογή καταχωρήσεων \r\n\tτου πρόχειρου.\r\n\ /n\tΆνοιγμα πάντα νέου παραθύρου (/ns παρουσία ενός μόνο αρχείου).\r\n\ -/r\tΕπαναχρησιμοποίηση παραθύρου (/rs παρουσία ενός μόνο\r\n\tαρχείου).\r\n\ -/p\tΟρισμός θέσης και μεγέθους παραθύρου (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tή /p <αριστερά>,<πάνω>,<πλάτος>,<ύψος>[,,<μέγ.>] [όλοι\r\n\tακέραιοι].\r\n\ +/r\tΕπαναχρησιμοποίηση παραθύρου (/rs παρουσία ενός μόνο αρχείου).\r\n\ +/p\tΟρισμός θέσης και μεγέθους παραθύρου (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tή /p <αριστερά>,<πάνω>,<πλάτος>,<ύψος>[,,<μέγ.>] [όλοι ακέραιοι].\r\n\ /t\tΟρισμός τίτλου παραθύρου.\r\n\ /i\tΈναρξη ως ελαχιστοποιημένο στην περιοχή ειδοποιήσεων.\r\n\ /o\tΠάντα στην κορυφή το παράθυρο.\r\n\ @@ -324,11 +325,11 @@ Notepad3 [/?] [...[Κωδικοποίηση]] [...[Λειτουργία κατά /u\tΕκκίνηση με αυξημένα δικαιώματα.\r\n\ /v\tΕκτύπωση αρχείου άμεσα και έξοδος.\r\n\ /vd\tΕκτύπωση αρχείου (άνοιγμα διαλόγου εκτυπωτή).\r\n\ -/y\tΑναζήτηση στο περιβάλλον PATH σε περίπτωση σχετικού ονόματος\r\n\tαρχείου.\r\n\ -/z\tΜετάβαση στο επόμενο (χρησιμοποιείται για αντικατάσταση\r\n\tτου Notepad μέσω του μητρώου).\r\n\r\n\ +/y\tΑναζήτηση στο περιβάλλον PATH σε περίπτωση σχετικού ονόματος αρχείου.\r\n\ +/z\tΜετάβαση στο επόμενο (χρησιμοποιείται για αντικατάσταση του Notepad \r\n\tμέσω του μητρώου).\r\n\r\n\ Παραδείγματα:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ - \t... Άνοιγμα νέου αρχείου: ""Test.txt"" Κωδικοποίηση=UTF-8-BOM,\r\n\tEoL=CRLF.\r\n\ + \t... Άνοιγμα νέου αρχείου: ""Test.txt"" Κωδικοποίηση=UTF-8-BOM, EoL=CRLF.\r\n\ Notepad3 /v d:\\temp\\Test.txt\r\n\ \t... Εκτύπωση του αρχείου: ""Test.txt"" άμεσα.\ " diff --git a/language/np3_en_gb/lexer_en_gb.rc b/language/np3_en_gb/lexer_en_gb.rc index 374d79963..b788f4763 100644 --- a/language/np3_en_gb/lexer_en_gb.rc +++ b/language/np3_en_gb/lexer_en_gb.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_en_gb/strings_en_gb.rc b/language/np3_en_gb/strings_en_gb.rc index a5513da3a..5cc4e6ca7 100644 --- a/language/np3_en_gb/strings_en_gb.rc +++ b/language/np3_en_gb/strings_en_gb.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s occurrence(s) of specified search pattern replaced." IDS_MUI_ASK_ENCODING "Switching the file encoding from one encoding to another may replace unsupported text with default characters, and the undo history will be cleared. Continue?" IDS_MUI_ASK_ENCODING2 "You are about to change the encoding of an empty file. Note that this will clear the undo history, as it can't be synchronised with the new encoding. Continue?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" is read only. Save to a different file?" IDS_MUI_FILECHANGENOTIFY "The current file has been modified by an external program. Reload?" @@ -315,8 +316,8 @@ Options:\r\n\ /b\tOpen new paste board to collect clipboard entries.\r\n\ /n\tAlways open a new window (/ns single file instance).\r\n\ /r\tReuse window (/rs single file instance).\r\n\ -/p\tSet window position and size (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tor /p ,,,[,,] [all integers].\r\n\ +/p\tSet window position and size (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tor /p ,,,[,,] [all integers].\r\n\ /t\tSet window title.\r\n\ /i\tStart as tray icon.\r\n\ /o\tKeep window on top.\r\n\ diff --git a/language/np3_en_us/strings_en_us.rc b/language/np3_en_us/strings_en_us.rc index b83367750..2c8c9e9ff 100644 --- a/language/np3_en_us/strings_en_us.rc +++ b/language/np3_en_us/strings_en_us.rc @@ -316,8 +316,8 @@ Options:\r\n\ /b\tOpen new paste board to collect clipboard entries.\r\n\ /n\tAlways open a new window (/ns single file instance).\r\n\ /r\tReuse window (/rs single file instance).\r\n\ -/p\tSet window position and size (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tor /p ,,,[,,] [all integers].\r\n\ +/p\tSet window position and size (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tor /p ,,,[,,] [all integers].\r\n\ /t\tSet window title.\r\n\ /i\tStart as tray icon.\r\n\ /o\tKeep window on top.\r\n\ diff --git a/language/np3_es_es/dialogs_es_es.rc b/language/np3_es_es/dialogs_es_es.rc index e140c0347..8b159c0e8 100644 --- a/language/np3_es_es/dialogs_es_es.rc +++ b/language/np3_es_es/dialogs_es_es.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 330, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Ayuda de la línea de comando" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "Aceptar",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "Aceptar",IDOK,269,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,308,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_es_es/lexer_es_es.rc b/language/np3_es_es/lexer_es_es.rc index c4c58fb0a..d44a02b8b 100644 --- a/language/np3_es_es/lexer_es_es.rc +++ b/language/np3_es_es/lexer_es_es.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_es_es/strings_es_es.rc b/language/np3_es_es/strings_es_es.rc index a762fe271..eabcf6cb7 100644 --- a/language/np3_es_es/strings_es_es.rc +++ b/language/np3_es_es/strings_es_es.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "Se han reemplazado %s ocurrencia(s) del patrón de búsqueda especificado." IDS_MUI_ASK_ENCODING "Cambiar la codificación del archivo de una codificación a otra puede reemplazar el texto no compatible con caracteres predeterminados, y el historial de deshacer se borrará. ¿Continuar?" IDS_MUI_ASK_ENCODING2 "Está a punto de cambiar la codificación de un archivo vacío. Tenga en cuenta que esto borrará el historial de deshacer, ya que no se puede sincronizar con la nueva codificación. ¿Continuar?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" es de sólo lectura. ¿Guardar en un archivo diferente?" IDS_MUI_FILECHANGENOTIFY "El archivo actual ha sido modificado por un programa externo. ¿Recargar?" @@ -295,8 +296,8 @@ Uso:\r\n\ Notepad3 [/?] [...[Codificación]] [...[Modo de final de línea]] [/e] [/g] [/m] [/l]\r\n\ \t[/q] [/s] [/d] [/h] [/x] [/c] [/b] [/n] [/r| [/p] [/t] [/i] [/o]\r\n\ \t[/f] [/u] [/v] [/vd] [/y] [/z] [[unidad:][ruta]archivo[...]]\r\n\r\n\ -archivo\tDebe ser el último argumento, sin espacios entre\r\n\tcomillas por defecto.\r\n\ -+\tAceptar múltiples argumentos de archivo (con espacios\r\n\tentre comillas).\r\n\ +archivo\tDebe ser el último argumento, sin espacios entre comillas por defecto.\r\n\ ++\tAceptar múltiples argumentos de archivo (con espacios entre comillas).\r\n\ -\tAceptar argumento de archivo único (sin espacios entre comillas).\r\n\r\n\ Opciones:\r\n\ /?\tMostrar este mensaje de ayuda.\r\n\ @@ -304,7 +305,7 @@ Opciones:\r\n\ ...\tModo de final de línea (/crlf, /cr, /lf).\r\n\ /e\tCodificación de la fuente del archivo.\r\n\ /g\tSaltar a la posición especificada (/g -1 fin de archivo).\r\n\ -/m\tCoincidencia de texto especificado (/m- último, /mr regex,\r\n\t/mb backslash).\r\n\ +/m\tCoincidencia de texto especificado (/m- último, /mr regex, /mb backslash).\r\n\ /l\tAuto recargar archivos modificados.\r\n\ /q\tForzar la creación de nuevos archivos sin aviso.\r\n\ /s\tSeleccione el esquema de sintaxis especificado.\r\n\ @@ -312,11 +313,11 @@ Opciones:\r\n\ /h\tSeleccione un esquema de código fuente Web.\r\n\ /x\tSeleccione el esquema de documento XML.\r\n\ /c\tAbrir nueva ventana y pegar contenido del portapapeles.\r\n\ -/b\tAbre una nueva tabla de pegar para recoger las entradas\r\n\tdel portapapeles.\r\n\ +/b\tAbre una nueva tabla de pegar para recoger las entradas del portapapeles.\r\n\ /n\tSiempre abre una nueva ventana (/ns instancia de archivo único).\r\n\ /r\tReutilizar la ventana (/rs instancia de archivo único).\r\n\ -/p\tEstablecer el tamaño y la posición de la ventana (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\to /p ,,,[,,] [todos\r\n\tenteros].\r\n\ +/p\tEstablecer el tamaño y la posición de la ventana (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\to /p ,,,[,,] [todos enteros].\r\n\ /t\tEstablecer el título de la ventana.\r\n\ /i\tComenzar como un icono de la barra de tareas.\r\n\ /o\tVentana siempre visible.\r\n\ @@ -325,10 +326,10 @@ Opciones:\r\n\ /v\tImprimir el archivo inmediatamente y salir.\r\n\ /vd\tImprimir archivo (abrir el cuadro de diálogo de la impresora).\r\n\ /y\tEntorno de búsqueda PATH en caso de nombre de archivo relativo..\r\n\ -/z\tIr a la siguiente (usar para reemplazar el Notepad basado\r\n\ten el registro).\r\n\r\n\ +/z\tIr a la siguiente (usar para reemplazar el Notepad basado en el registro).\r\n\r\n\ Ejemplos:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ - \t... Abrir un nuevo archivo: ""Test.txt"" Codificación=UTF-8-BOM,\r\n\tEoL=CRLF.\r\n\ + \t... Abrir un nuevo archivo: ""Test.txt"" Codificación=UTF-8-BOM, EoL=CRLF.\r\n\ Notepad3 /v d:\\temp\\Test.txt\r\n\ \t... Imprimir el archivo: ""Test.txt"" inmediatamente.\ " diff --git a/language/np3_es_mx/dialogs_es_mx.rc b/language/np3_es_mx/dialogs_es_mx.rc index 6d8e188d0..eb99ff806 100644 --- a/language/np3_es_mx/dialogs_es_mx.rc +++ b/language/np3_es_mx/dialogs_es_mx.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 330, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Ayuda de la línea de comando" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "Aceptar",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "Aceptar",IDOK,269,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,308,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_es_mx/lexer_es_mx.rc b/language/np3_es_mx/lexer_es_mx.rc index bef36a66d..9903fa56f 100644 --- a/language/np3_es_mx/lexer_es_mx.rc +++ b/language/np3_es_mx/lexer_es_mx.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_es_mx/strings_es_mx.rc b/language/np3_es_mx/strings_es_mx.rc index dbd4de1a4..119b6bb3a 100644 --- a/language/np3_es_mx/strings_es_mx.rc +++ b/language/np3_es_mx/strings_es_mx.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "Se han reemplazado %s ocurrencia(s) del patrón de búsqueda especificado." IDS_MUI_ASK_ENCODING "Cambiar la codificación del archivo de una codificación a otra puede reemplazar el texto no compatible con caracteres predeterminados, y el historial de deshacer se borrará. ¿Continuar?" IDS_MUI_ASK_ENCODING2 "Está a punto de cambiar la codificación de un archivo vacío. Tenga en cuenta que esto borrará el historial de deshacer, ya que no se puede sincronizar con la nueva codificación. ¿Continuar?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" es de sólo lectura. ¿Guardar en un archivo diferente?" IDS_MUI_FILECHANGENOTIFY "El archivo actual ha sido modificado por un programa externo. ¿Recargar?" @@ -295,8 +296,8 @@ Uso:\r\n\ Notepad3 [/?] [...[Codificación]] [...[Modo de final de línea]] [/e] [/g] [/m] [/l]\r\n\ \t[/q] [/s] [/d] [/h] [/x] [/c] [/b] [/n] [/r| [/p] [/t] [/i] [/o]\r\n\ \t[/f] [/u] [/v] [/vd] [/y] [/z] [[unidad:][ruta]archivo[...]]\r\n\r\n\ -archivo\tDebe ser el último argumento, sin espacios entre\r\n\tcomillas por defecto.\r\n\ -+\tAceptar múltiples argumentos de archivo (con espacios\r\n\tentre comillas).\r\n\ +archivo\tDebe ser el último argumento, sin espacios entre comillas por defecto.\r\n\ ++\tAceptar múltiples argumentos de archivo (con espacios entre comillas).\r\n\ -\tAceptar argumento de archivo único (sin espacios entre comillas).\r\n\r\n\ Opciones:\r\n\ /?\tMostrar este mensaje de ayuda.\r\n\ @@ -304,7 +305,7 @@ Opciones:\r\n\ ...\tModo de final de línea (/crlf, /cr, /lf).\r\n\ /e\tCodificación de la fuente del archivo.\r\n\ /g\tSaltar a la posición especificada (/g -1 fin de archivo).\r\n\ -/m\tCoincidencia de texto especificado (/m- último, /mr regex,\r\n\t/mb backslash).\r\n\ +/m\tCoincidencia de texto especificado (/m- último, /mr regex, /mb backslash).\r\n\ /l\tAuto recargar archivos modificados.\r\n\ /q\tForzar la creación de nuevos archivos sin aviso.\r\n\ /s\tSeleccione el esquema de sintaxis especificado.\r\n\ @@ -312,11 +313,11 @@ Opciones:\r\n\ /h\tSeleccione un esquema de código fuente Web.\r\n\ /x\tSeleccione el esquema de documento XML.\r\n\ /c\tAbrir nueva ventana y pegar contenido del portapapeles.\r\n\ -/b\tAbre una nueva tabla de pegar para recoger las entradas\r\n\tdel portapapeles.\r\n\ +/b\tAbre una nueva tabla de pegar para recoger las entradas del portapapeles.\r\n\ /n\tSiempre abre una nueva ventana (/ns instancia de archivo único).\r\n\ /r\tReutilizar la ventana (/rs instancia de archivo único).\r\n\ -/p\tEstablecer el tamaño y la posición de la ventana (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\to /p ,,,[,,] [todos\r\n\tenteros].\r\n\ +/p\tEstablecer el tamaño y la posición de la ventana (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\to /p ,,,[,,] [todos enteros].\r\n\ /t\tEstablecer el título de la ventana.\r\n\ /i\tComenzar como un icono de la barra de tareas.\r\n\ /o\tVentana siempre visible.\r\n\ @@ -325,10 +326,10 @@ Opciones:\r\n\ /v\tImprimir el archivo inmediatamente y salir.\r\n\ /vd\tImprimir archivo (abrir el cuadro de diálogo de la impresora).\r\n\ /y\tEntorno de búsqueda PATH en caso de nombre de archivo relativo..\r\n\ -/z\tIr a la siguiente (usar para reemplazar el Notepad basado\r\n\ten el registro).\r\n\r\n\ +/z\tIr a la siguiente (usar para reemplazar el Notepad basado en el registro).\r\n\r\n\ Ejemplos:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ - \t... Abrir un nuevo archivo: ""Test.txt"" Codificación=UTF-8-BOM,\r\n\tEoL=CRLF.\r\n\ + \t... Abrir un nuevo archivo: ""Test.txt"" Codificación=UTF-8-BOM, EoL=CRLF.\r\n\ Notepad3 /v d:\\temp\\Test.txt\r\n\ \t... Imprimir el archivo: ""Test.txt"" inmediatamente.\ " diff --git a/language/np3_fr_fr/dialogs_fr_fr.rc b/language/np3_fr_fr/dialogs_fr_fr.rc index 4989f2757..6de07bf80 100644 --- a/language/np3_fr_fr/dialogs_fr_fr.rc +++ b/language/np3_fr_fr/dialogs_fr_fr.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 330, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Aide de la ligne de commande" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,269,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,308,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 278, 142 diff --git a/language/np3_fr_fr/lexer_fr_fr.rc b/language/np3_fr_fr/lexer_fr_fr.rc index e12d986f8..76b84dff6 100644 --- a/language/np3_fr_fr/lexer_fr_fr.rc +++ b/language/np3_fr_fr/lexer_fr_fr.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Opérateur de symbole" IDS_LEX_STR_63388 "Chaîne EOL" IDS_LEX_STR_63397 "Accents graves" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_fr_fr/strings_fr_fr.rc b/language/np3_fr_fr/strings_fr_fr.rc index 1dd6673b3..d10596454 100644 --- a/language/np3_fr_fr/strings_fr_fr.rc +++ b/language/np3_fr_fr/strings_fr_fr.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s occurrence(s) du modèle de recherche spécifié remplacée(s)." IDS_MUI_ASK_ENCODING "Changer l'encodage du fichier d'un encodage à un autre peut remplacer le texte non pris en charge par des caractères par défaut et l'historique de ""Défaire"" sera effacé. Continuer ?" IDS_MUI_ASK_ENCODING2 "Vous êtes sur le point de changer l'encodage d'un fichier vide. Notez que cela effacera l'historique de ""Défaire"", car il ne peut pas être synchronisé avec le nouvel encodage. Continuer ?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" est en lecture seule. Sauvegarder dans un fichier différent ?" IDS_MUI_FILECHANGENOTIFY "Le fichier actuel a été modifié par un programme externe. Recharger ?" @@ -295,8 +296,8 @@ Utilisation :\r\n\ Notepad3 [/?] [...[Encodage]] [...[Mode de fin de ligne]] [/e] [/g] [/m]\r\n\ \t[/l] [/q] [/s] [/d] [/h] [/x] [/c] [/b] [/n] [/r| [/p] [/t] [/i] [/o]\r\n\ \t[/f] [/u] [/v] [/vd] [/y] [/z] [[lecteur:][chemin]fichier[...]]\r\n\r\n\ -fichier\tDoit être le dernier argument, aucun espace entre guillemets\r\n\tpar défaut.\r\n\ -+\tAccepte plusieurs arguments de fichier (avec des espaces entre\r\n\tguillemets).\r\n\ +fichier\tDoit être le dernier argument, aucun espace entre guillemets par défaut.\r\n\ ++\tAccepte plusieurs arguments de fichier (avec des espaces entre guillemets).\r\n\ -\tAccepte un seul argument de fichier (sans espaces entre guillemets).\r\n\r\n\ Options :\r\n\ /?\tAffiche ce message d'aide.\r\n\ @@ -304,7 +305,7 @@ Options :\r\n\ ...\tMode de fin de ligne (/crlf, /cr, /lf).\r\n\ /e\tEncodage du fichier source.\r\n\ /g\tVa à la position spécifiée (/g -1 fin de fichier).\r\n\ -/m\tTrouve le texte spécifié (/m- dernier, /mr regex,\r\n\t/mb oblique inverse).\r\n\ +/m\tTrouve le texte spécifié (/m- dernier, /mr regex, /mb oblique inverse).\r\n\ /l\tRecharge automatiquement les fichiers modifiés.\r\n\ /q\tForce la création de nouveaux fichiers sans confirmation.\r\n\ /s\tSélectionne le modèle de syntaxe spécifié.\r\n\ @@ -312,11 +313,11 @@ Options :\r\n\ /h\tSélectionne un modèle de Code Source Web.\r\n\ /x\tSélectionne un modèle de Document XML.\r\n\ /c\tOuvre une nouvelle fenêtre et colle le contenu du presse-papiers.\r\n\ -/b\tOuvre un nouveau tableau de collage pour collecter les entrées du\r\n\tpresse-papiers.\r\n\ -/n\tOuvre toujours une nouvelle fenêtre (/ns instance\r\n\tde fichier unique).\r\n\ +/b\tOuvre un nouveau tableau de collage pour collecter les entrées du \r\n\tpresse-papiers.\r\n\ +/n\tOuvre toujours une nouvelle fenêtre (/ns instance de fichier unique).\r\n\ /r\tRéutilise la fenêtre (/rs instance de fichier unique).\r\n\ -/p\tDéfinit la position et la taille de la fenêtre (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tou /p ,,,[,,] [tous entiers].\r\n\ +/p\tDéfinit la position et la taille de la fenêtre (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tou /p ,,,[,,] [tous entiers].\r\n\ /t\tDéfinit un titre de fenêtre.\r\n\ /i\tDémarre en icône dans la zone de notifications.\r\n\ /o\tGarde la fenêtre toujours visible.\r\n\ @@ -324,11 +325,11 @@ Options :\r\n\ /u\tDémarre avec des privilèges élevés.\r\n\ /v\tImprime le fichier immédiatement et quitte.\r\n\ /vd\tImprime le fichier (ouvre le dialogue de l'imprimante).\r\n\ -/y\tCherche dans le PATH (environnement) en cas de nom de fichier\r\n\trelatif.\r\n\ -/z\tPasse au suivant (utilisable avec le remplacement de Notepad via\r\n\tle registre).\r\n\r\n\ +/y\tCherche dans le PATH (environnement) en cas de nom de fichier relatif.\r\n\ +/z\tPasse au suivant (utilisable avec le remplacement de Notepad via le registre).\r\n\r\n\ Exemples :\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ - \t... Ouvre un nouveau fichier : ""Test.txt"" Encodage=UTF-8-BOM,\r\n\tEoL=CRLF.\r\n\ + \t... Ouvre un nouveau fichier : ""Test.txt"" Encodage=UTF-8-BOM, EoL=CRLF.\r\n\ Notepad3 /v d:\\temp\\Test.txt\r\n\ \t... Imprime le fichier : ""Test.txt"" immédiatement.\ " diff --git a/language/np3_hi_in/dialogs_hi_in.rc b/language/np3_hi_in/dialogs_hi_in.rc index c8e1f65dc..961d73a92 100644 --- a/language/np3_hi_in/dialogs_hi_in.rc +++ b/language/np3_hi_in/dialogs_hi_in.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 310, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "कमांड लाइन मदद" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "सही है",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "सही है",IDOK,249,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,288,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_hi_in/lexer_hi_in.rc b/language/np3_hi_in/lexer_hi_in.rc index ce31339ef..29cb1c472 100644 --- a/language/np3_hi_in/lexer_hi_in.rc +++ b/language/np3_hi_in/lexer_hi_in.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_hi_in/strings_hi_in.rc b/language/np3_hi_in/strings_hi_in.rc index 41f9d4856..0458b7025 100644 --- a/language/np3_hi_in/strings_hi_in.rc +++ b/language/np3_hi_in/strings_hi_in.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "निर्देशित खोज पैटर्न के अनुसार %s उपस्थितियाँ बदल दी गई हैं " IDS_MUI_ASK_ENCODING "फ़ाईल एन्कोडिंग बदलने के स्वरूप निराधार टेक्स्ट डिफ़ॉल्ट वर्णों से बदल सकते हैं, और पूर्ववत करने का इतिहास भी साफ़ हो जाएगा। शुरू करें?" IDS_MUI_ASK_ENCODING2 "आप एक खाली फ़ाईल की एन्कोडिंग बदलने जा रहे हैं। ध्यान दें कि यह कार्य पूर्ववत करने का इतिहास भी साफ़ कर देगा, क्यूंकि यह नई एन्कोडिंग के साथ sync नहीं हो सकता. शुरू करें?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" सिर्फ़ पढ़ने-लायक है। अन्य फ़ाईल के रूप में सहेजें?" IDS_MUI_FILECHANGENOTIFY "चालू फ़ाईल एक बाहरी प्रोग्राम द्वारा परिवर्तित हो चुकी है। पुनः लोड करें?" @@ -315,8 +316,8 @@ Notepad3 [/?] [...[एन्कोडिंग]] [...[रेखा समाप /b\tक्लिपबोर्ड प्रविष्टियाँ जमा करने हेतु नए पेस्ट बोर्ड को खोलें.\r\n\ /n\tसदैव एक नई विंडो खोलें (/ns एकल फ़ाइल अवस्था).\r\n\ /r\tविंडो पुनः इस्तमएआल करें (/rs एकल फ़ाइल अवस्था).\r\n\ -/p\tविंडो स्तिथि और आकार तय करें (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tया /p <बाएं>,<शीर्ष>,<चोड़ाई>,<ऊंचाई>[,,<अत्यधिक>] [समस्त पूर्णांक].\r\n\ +/p\tविंडो स्तिथि और आकार तय करें (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tया /p <बाएं>,<शीर्ष>,<चोड़ाई>,<ऊंचाई>[,,<अत्यधिक>] [समस्त पूर्णांक].\r\n\ /t\tविंडो शीर्षक तय करें.\r\n\ /i\tट्रे आइकान के रूप में शुरू करें.\r\n\ /o\tविंडो ऊपर रखें.\r\n\ diff --git a/language/np3_hu_hu/dialogs_hu_hu.rc b/language/np3_hu_hu/dialogs_hu_hu.rc index 3a874f2a8..95232d76f 100644 --- a/language/np3_hu_hu/dialogs_hu_hu.rc +++ b/language/np3_hu_hu/dialogs_hu_hu.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 320, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Parancssori súgó" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,259,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,298,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_hu_hu/lexer_hu_hu.rc b/language/np3_hu_hu/lexer_hu_hu.rc index d327d3ded..f441d344e 100644 --- a/language/np3_hu_hu/lexer_hu_hu.rc +++ b/language/np3_hu_hu/lexer_hu_hu.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_hu_hu/strings_hu_hu.rc b/language/np3_hu_hu/strings_hu_hu.rc index aa8299e18..9c1c071d0 100644 --- a/language/np3_hu_hu/strings_hu_hu.rc +++ b/language/np3_hu_hu/strings_hu_hu.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "A keresési minta %s db. találata cserélve lett." IDS_MUI_ASK_ENCODING "A fájl kódolásának megváltoztatása lecserélhet nem támogatott karaktereket alapértelmezettek karakterekkel, valamint a visszavonási történet törölve lesz. Folytatja?" IDS_MUI_ASK_ENCODING2 "Egy üres fájl kódolását változtatja meg. Ne feledje, hogy ez a visszavonási történetet törli, mert azt nem lehet szinkronizálni az új kódolással. Folytatja?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" csak olvastható. Legyen mentés egy másik fájlba?" IDS_MUI_FILECHANGENOTIFY "Az aktuális fájl egy külső progarm által módosítva lett. Újratöltsük?" @@ -295,7 +296,7 @@ Használat:\r\n\ Notepad3 [/?] [...[kódolás]] [...[sorvég mód]] [/e] [/g] [/m] [/l]\r\n\ \t[/q] [/s] [/d] [/h] [/x] [/c] [/b] [/n] [/r| [/p] [/t] [/i] [/o]\r\n\ \t[/f] [/u] [/v] [/vd] [/y] [/z] [[meghajtó:][útvonal]fájlnév[...]]\r\n\r\n\ -fájl\tAz utolsó paraméter kell legyen, alapból nincsenek idézőjelezett\r\n\tszóközök.\r\n\ +fájl\tAz utolsó paraméter kell legyen, alapból nincsenek idézőjelezett szóközök.\r\n\ +\tTöbb fájlt is elfogad (idézőjelezett szóközökkel).\r\n\ -\tEgy fájlt fogad el paraméterként (idézőjelezett szóközök nélkül).\r\n\r\n\ Opciók:\r\n\ @@ -315,8 +316,8 @@ Opciók:\r\n\ /b\tÚj dokumentum megnyitása, ahova a vágólap tartalma gyűlik.\r\n\ /n\tMindig nyisson új ablakot (/ns egyetlen fájl példány).\r\n\ /r\tAblak újrahasznosítása (/rs egyetlen fájl példány).\r\n\ -/p\tAblak pozíció és méret beállítása (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tor /p ,,,[,,] [mindegyik\r\n\tegész szám].\r\n\ +/p\tAblak pozíció és méret beállítása (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tor /p ,,,[,,] [mindegyik \r\n\tegész szám].\r\n\ /t\tCímsor szövegének beállítása.\r\n\ /i\tIndítás óra melé kicsinyítve.\r\n\ /o\tAblak mindig felül.\r\n\ @@ -325,7 +326,7 @@ Opciók:\r\n\ /v\tFájl nyomtatása rögtön és kilépés.\r\n\ /vd\tFájl nyomtatása (Nyomtatási ablak megnyitása).\r\n\ /y\tRelatív fájlnév esetén keressen az útvonalon (PATH) belül.\r\n\ -/z\tKövetkező kihagyása (registry alapú Notepad lecserélésnél lehet\r\n\thasznos).\r\n\r\n\ +/z\tKövetkező kihagyása (registry alapú Notepad lecserélésnél lehet hasznos).\r\n\r\n\ Példák:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ \t... Egy új fájlt nyit meg: ""Test.txt"" Encoding=UTF-8-BOM, EoL=CRLF.\r\n\ diff --git a/language/np3_id_id/lexer_id_id.rc b/language/np3_id_id/lexer_id_id.rc index f722bcf91..2d87101cd 100644 --- a/language/np3_id_id/lexer_id_id.rc +++ b/language/np3_id_id/lexer_id_id.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_id_id/strings_id_id.rc b/language/np3_id_id/strings_id_id.rc index 418635b46..fecc8a026 100644 --- a/language/np3_id_id/strings_id_id.rc +++ b/language/np3_id_id/strings_id_id.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s occurrence(s) of specified search pattern replaced." IDS_MUI_ASK_ENCODING "Switching the file encoding from one encoding to another may replace unsupported text with default characters, and the undo history will be cleared. Continue?" IDS_MUI_ASK_ENCODING2 "You are about to change the encoding of an empty file. Note that this will clear the undo history, as it can't be synchronised with the new encoding. Continue?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" is read only. Save to a different file?" IDS_MUI_FILECHANGENOTIFY "The current file has been modified by an external program. Reload?" @@ -315,8 +316,8 @@ Options:\r\n\ /b\tOpen new paste board to collect clipboard entries.\r\n\ /n\tAlways open a new window (/ns single file instance).\r\n\ /r\tReuse window (/rs single file instance).\r\n\ -/p\tSet window position and size (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tor /p ,,,[,,] [all integers].\r\n\ +/p\tSet window position and size (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tor /p ,,,[,,] [all integers].\r\n\ /t\tSet window title.\r\n\ /i\tStart as tray icon.\r\n\ /o\tKeep window on top.\r\n\ diff --git a/language/np3_it_it/lexer_it_it.rc b/language/np3_it_it/lexer_it_it.rc index c98616a8d..f9b8008d3 100644 --- a/language/np3_it_it/lexer_it_it.rc +++ b/language/np3_it_it/lexer_it_it.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Operatore Simbolo" IDS_LEX_STR_63388 "Stringa EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_it_it/strings_it_it.rc b/language/np3_it_it/strings_it_it.rc index cb3e3ce18..8602ea319 100644 --- a/language/np3_it_it/strings_it_it.rc +++ b/language/np3_it_it/strings_it_it.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s occorrenze del pattern di ricerca specificato sono state sostituite." IDS_MUI_ASK_ENCODING "Cambiare la codifica del file potrebbe sostituire testo non supportato con un carattere di default, e la cronologia delle modifiche (undo) sarà svuotata. Continuare?" IDS_MUI_ASK_ENCODING2 "Stai per cambiare la codifica di un file vuoto. Questo cancellerà la cronologia delle modifiche (undo), perché non può essere sincronizzata con la nuova codifica. Continuare?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" è in sola lettura. Salvare in un file differente?" IDS_MUI_FILECHANGENOTIFY "Il file corrente è stato modificato da un programma esterno. Ricaricare?" @@ -315,8 +316,8 @@ Opzioni:\r\n\ /b\tApri una nuova Paste Board per collezionare il testo copiato\r\n\tnegli Appunti.\r\n\ /n\tApri sempre una nuova finestra (/ns istanza singola).\r\n\ /r\tRiutilizza finestra (/rs istanza singola).\r\n\ -/p\tImposta posizione e dimensione della finestra (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\to /p ,,,[,,] [numeri interi].\r\n\ +/p\tImposta posizione e dimensione della finestra (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\to /p ,,,[,,] \r\n\t[numeri interi].\r\n\ /t\tImposta titolo della finestra.\r\n\ /i\tAvvia come icona nell'area di notifica'.\r\n\ /o\tMantieni finestra in primo piano.\r\n\ diff --git a/language/np3_ja_jp/lexer_ja_jp.rc b/language/np3_ja_jp/lexer_ja_jp.rc index b51eecc19..90c96d4e1 100644 --- a/language/np3_ja_jp/lexer_ja_jp.rc +++ b/language/np3_ja_jp/lexer_ja_jp.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "文字列 EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_ja_jp/strings_ja_jp.rc b/language/np3_ja_jp/strings_ja_jp.rc index e12f25921..654ac60b5 100644 --- a/language/np3_ja_jp/strings_ja_jp.rc +++ b/language/np3_ja_jp/strings_ja_jp.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "一致する %s か所を指定の検索条件で置換しました。" IDS_MUI_ASK_ENCODING "他の文字コードに変換すると、未対応の文字は所定の文字に置換され、また「元に戻す」の履歴もリセットされます。\n変換を続行しますか?" IDS_MUI_ASK_ENCODING2 "空のファイルの文字コードを変更しようとしています。「元に戻す」の履歴もリセットされます。変更を続行しますか?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE "「%s」は読み取り専用です。別のファイル名で保存しますか?" IDS_MUI_FILECHANGENOTIFY "ファイルが他のプログラムによって変更されました。再読み込みしますか?" @@ -304,7 +305,7 @@ Notepad3 [/?] [...[文字コード]] [...[改行コード]] [/e] [/g] [/m] [/l]\ ...\t改行コード (/crlf, /cr, /lf)\r\n\ /e\tファイルの文字コードを指定 [/e id]\r\n\ /g\t指定位置にジャンプ (/g 行[,列] -1で終端)\r\n\ -/m\t文字列一致 [/m text] (/m- 最後, /mr 正規表現,\r\n\t/mb バックスラッシュ変換)\r\n\ +/m\t文字列一致 [/m text] (/m- 最後, /mr 正規表現, /mb バックスラッシュ変換)\r\n\ /l\tファイル変更時に自動で最新内容に再読み込み\r\n\ /q\tファイルがない場合、問い合わせずファイル作成\r\n\ /s\t配色設定を指定 [/s ext]\r\n\ @@ -315,8 +316,8 @@ Notepad3 [/?] [...[文字コード]] [...[改行コード]] [/e] [/g] [/m] [/l]\ /b\tクリップボード履歴表示モードで開く\r\n\ /n\t新規ウィンドウで開く (/ns ファイルは単一のインスタンス)\r\n\ /r\tウインドウを再利用 (/rs 同じく単一のインスタンス\r\n\ -/p\tウィンドウの位置とサイズを指定 [/p x,y,sizex,y[,max]] (/p0, /ps, /pf,\r\n\ -\tl,t,r,b,m) or /p ,,,[,,] [すべて整数]\r\n\ +/p\tウィンドウの位置とサイズを指定 (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tor /p ,,,[,,] [すべて整数]\r\n\ /t\tタイトルバーの文字列を指定 [/t text]\r\n\ /i\tシステムトレイ内に起動\r\n\ /o\t常に手前に表示\r\n\ diff --git a/language/np3_ko_kr/lexer_ko_kr.rc b/language/np3_ko_kr/lexer_ko_kr.rc index efde40c46..164851937 100644 --- a/language/np3_ko_kr/lexer_ko_kr.rc +++ b/language/np3_ko_kr/lexer_ko_kr.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "기호 연산자" IDS_LEX_STR_63388 "문자열 EOL" IDS_LEX_STR_63397 "백틱" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_ko_kr/strings_ko_kr.rc b/language/np3_ko_kr/strings_ko_kr.rc index 5d30aa555..b669e155a 100644 --- a/language/np3_ko_kr/strings_ko_kr.rc +++ b/language/np3_ko_kr/strings_ko_kr.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "지정한 검색 패턴의 %s 발생이 대체되었습니다." IDS_MUI_ASK_ENCODING "파일 인코딩을 한 인코딩에서 다른 인코딩으로 전환하면 지원되지 않는 텍스트가 기본 문자로 대체될 수 있으며 실행 취소 기록이 지워집니다. 계속하시겠습니까?" IDS_MUI_ASK_ENCODING2 "빈 파일의 인코딩을 변경하려고 합니다. 새 인코딩과 동기화할 수 없기 때문에 실행 취소 기록이 지워집니다. 계속하시겠습니까?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s""은 읽기 전용입니다. 다른 파일로 저장하시겠습니까?" IDS_MUI_FILECHANGENOTIFY "현재 파일이 외부 프로그램에 의해 수정되었습니다. 다시 불러오시겠습니까?" @@ -315,8 +316,8 @@ Notepad3 [/?] [...[인코딩]] [...[줄 끝 모드]] [/e] [/g] [/m] [/l]\r\n\ /b\t새 붙여넣기 보드를 열어 클립보드 항목을 수집합니다.\r\n\ /n\t항상 새 창을 엽니다 (/ns 단일 파일 인스턴스).\r\n\ /r\t창을 재사용합니다 (/rs 단일 파일 인스턴스).\r\n\ -/p\t창 위치와 크기 지정 (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\t또는 /p <왼쪽>,<상단>,<너비>,<높이>[,,<최대>] [모두 정수].\r\n\ +/p\t창 위치와 크기 지정 (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\t또는 /p <왼쪽>,<상단>,<너비>,<높이>[,,<최대>] [모두 정수].\r\n\ /t\t창 제목을 설정합니다.\r\n\ /i\t트레이 아이콘으로 시작합니다.\r\n\ /o\t창을 맨 위에 둡니다.\r\n\ diff --git a/language/np3_nl_nl/dialogs_nl_nl.rc b/language/np3_nl_nl/dialogs_nl_nl.rc index 1552d1995..729af218a 100644 --- a/language/np3_nl_nl/dialogs_nl_nl.rc +++ b/language/np3_nl_nl/dialogs_nl_nl.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 320, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Hulp bij de opdrachtregel" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,259,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,298,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_nl_nl/lexer_nl_nl.rc b/language/np3_nl_nl/lexer_nl_nl.rc index 59242617a..0c416d0a6 100644 --- a/language/np3_nl_nl/lexer_nl_nl.rc +++ b/language/np3_nl_nl/lexer_nl_nl.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_nl_nl/strings_nl_nl.rc b/language/np3_nl_nl/strings_nl_nl.rc index 8b13f1f56..86a7e66d5 100644 --- a/language/np3_nl_nl/strings_nl_nl.rc +++ b/language/np3_nl_nl/strings_nl_nl.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s exempla(a)r(en) van het opgegeven zoekpatroon vervangen." IDS_MUI_ASK_ENCODING "Bij het omzetten van de ene naar de andere codering kan niet-ondersteunde tekst worden vervangen door standaardtekens. Dit kan niet ongedaan worden. Doorgaan?" IDS_MUI_ASK_ENCODING2 "Je staat op het punt de codering van een leeg bestand te wijzigen. Dit kan niet ongedaan worden. Doorgaan?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" is alleen-lezen. Opslaan als een ander bestand?" IDS_MUI_FILECHANGENOTIFY "Het huidige bestand is gewijzigd door een extern programma. Opnieuw laden?" @@ -295,9 +296,9 @@ Gebruik:\r\n\ Notepad3 [/?] [...[Codering]] [...[Regeleinde-modus]] [/e] [/g] [/m] [/l]\r\n\ \t[/q] [/s] [/d] [/h] [/x] [/c] [/b] [/n] [/r| [/p] [/t] [/i] [/o]\r\n\ \t[/f] [/u] [/v] [/vd] [/y] [/z] [[schijf:][pad]bestand[...]]\r\n\r\n\ -bestand\tMoet het laatste argument zijn, geen aanhalingstekens\r\n\tspaties standaard.\r\n\ -+\tAccepteer meerdere bestandsargumenten (met\r\n\taanhalingstekens spaties).\r\n\ --\tAccepteer argument voor een enkel bestand (zonder\r\n\taanhalingstekens).\r\n\r\n\ +bestand\tMoet het laatste argument zijn, geen aanhalingstekens spaties standaard.\r\n\ ++\tAccepteer meerdere bestandsargumenten (met aanhalingstekens spaties).\r\n\ +-\tAccepteer argument voor een enkel bestand (zonder aanhalingstekens).\r\n\r\n\ Opties:\r\n\ /?\tDeze gebruiksaanwijzing weergeven.\r\n\ ...\tCodering (/ansi, /unicode, /unicodebe, /utf8, /utf8sig).\r\n\ @@ -315,8 +316,8 @@ Opties:\r\n\ /b\tOpen nieuw plakbord om de klemborditems te verzamelen.\r\n\ /n\tOpen altijd een nieuw venster (/ns één bestand instantie).\r\n\ /r\tHergebruik venster (/rs één bestand instantie).\r\n\ -/p\tVensterpositie en -grootte instellen (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tof /p ,,,[,,] [gehele getallen].\r\n\ +/p\tVensterpositie en -grootte instellen (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tof /p ,,,[,,] [gehele\r\n\tgetallen].\r\n\ /t\tVenstertitel instellen.\r\n\ /i\tStart als systeemvakpictogram.\r\n\ /o\tVenster bovenop houden.\r\n\ @@ -325,7 +326,7 @@ Opties:\r\n\ /v\tBestand direct afdrukken en afsluiten.\r\n\ /vd\tBestand afdrukken (via printerdialoog).\r\n\ /y\tZoekomgeving PAD in geval van relatieve bestandsnaam.\r\n\ -/z\tVolgende overslaan (bruikbaar voor het register-gebaseerde\r\n\tNotepad vervanging).\r\n\r\n\ +/z\tVolgende overslaan (bruikbaar voor het register-gebaseerde Notepad\r\n\tvervanging).\r\n\r\n\ Voorbeelden:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ \t... Nieuw bestand openen: ""Test.txt"" Codering=UTF-8-BOM, EoL=CRLF.\r\n\ diff --git a/language/np3_pl_pl/dialogs_pl_pl.rc b/language/np3_pl_pl/dialogs_pl_pl.rc index 102b41178..3ef2d7d44 100644 --- a/language/np3_pl_pl/dialogs_pl_pl.rc +++ b/language/np3_pl_pl/dialogs_pl_pl.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 310, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Pomoc linii komend" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,249,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,288,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_pl_pl/lexer_pl_pl.rc b/language/np3_pl_pl/lexer_pl_pl.rc index d9dad554f..3f8b93cb1 100644 --- a/language/np3_pl_pl/lexer_pl_pl.rc +++ b/language/np3_pl_pl/lexer_pl_pl.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_pl_pl/strings_pl_pl.rc b/language/np3_pl_pl/strings_pl_pl.rc index 4d6e8edd8..cd06b06b0 100644 --- a/language/np3_pl_pl/strings_pl_pl.rc +++ b/language/np3_pl_pl/strings_pl_pl.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "Zamieniono %s wystąpień określonego wzorca wyszukiwania." IDS_MUI_ASK_ENCODING "Przełączanie kodowania pliku z jednego kodowania na drugie może zamienić tekst na domyślne znaki, i przywrócenie historii zostanie wymazane. Kontynuować?" IDS_MUI_ASK_ENCODING2 "Właśnie chcesz zmienić kodowanie pustego pliku. Spowoduje to wyczyszczenie historii, jak i również nie będzie możliwe zsynchronizowanie nowego kodowania. Kontynuować?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" tylko do odczytu. Zapisać do innego pliku?" IDS_MUI_FILECHANGENOTIFY "Bieżący plik został zmieniony przez zewnętrzny program. Załadować ponownie?" @@ -315,8 +316,8 @@ Opcje:\r\n\ /b\tOpen new paste board to collect clipboard entries.\r\n\ /n\tAlways open a new window (/ns single file instance).\r\n\ /r\tReuse window (/rs single file instance).\r\n\ -/p\tSet window position and size (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tor /p ,,,[,,] [wszystkie liczby].\r\n\ +/p\tSet window position and size (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tor /p ,,,[,,] [wszystkie liczby].\r\n\ /t\tSet window title.\r\n\ /i\tStart as tray icon.\r\n\ /o\tKeep window on top.\r\n\ diff --git a/language/np3_pt_br/dialogs_pt_br.rc b/language/np3_pt_br/dialogs_pt_br.rc index b825d9870..6f3d2fbd3 100644 --- a/language/np3_pt_br/dialogs_pt_br.rc +++ b/language/np3_pt_br/dialogs_pt_br.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 320, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Ajuda para Linha de Comando" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,259,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,298,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_pt_br/lexer_pt_br.rc b/language/np3_pt_br/lexer_pt_br.rc index d588a6a28..ce46fe02d 100644 --- a/language/np3_pt_br/lexer_pt_br.rc +++ b/language/np3_pt_br/lexer_pt_br.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Operador de Símbolos" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Acentos Graves" + IDS_LEX_STR_63398 "Cadeia GUID" END STRINGTABLE diff --git a/language/np3_pt_br/strings_pt_br.rc b/language/np3_pt_br/strings_pt_br.rc index f9531c9a0..1541376b2 100644 --- a/language/np3_pt_br/strings_pt_br.rc +++ b/language/np3_pt_br/strings_pt_br.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s ocorrência(s) substituída(s) do termo de pesquisa especificado." IDS_MUI_ASK_ENCODING "Mudar a codificação de um arquivo de uma codificação para outra pode levar à substituição de textos não suportados por caracteres padrão, e o histórico de ações para desfazer será apagado. Continuar?" IDS_MUI_ASK_ENCODING2 "Você está para mudar a codificação de um arquivo vazio. Note que isso apagará o histórico de ações para desfazer, já que ela não pode ser sincronizada com a nova codificação. Continuar?" + IDS_MUI_ASK_CLEAR_UNDO "Esta operação irá limpar o histórico de desfazer. Continuar?" IDS_MUI_READONLY_SAVE """%s"" é somente leitura. Salvar em um arquivo diferente?" IDS_MUI_FILECHANGENOTIFY "O presente arquivo foi modificado por um programa externo. Recarregar?" @@ -315,8 +316,8 @@ Opções:\r\n\ /b\tAbre um novo quadro de colagem para coletar entradas da área \r\n\tde transferência.\r\n\ /n\tSempre abre uma nova janela (/ns instância de único arquivo).\r\n\ /r\tReusa a janela (/rs instância de único arquivo).\r\n\ -/p\tDefine a posição e o tamanho da janela (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tou /p ,,,[,,] [all integers].\r\n\ +/p\tDefine a posição e o tamanho da janela (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tou /p ,,,[,,] [todos os números \r\n\tinteiros].\r\n\ /t\tDefine o título da janela.\r\n\ /i\tInicia como ícone na área de notificação.\r\n\ /o\tMantém a janela sobre as outras.\r\n\ @@ -324,8 +325,8 @@ Opções:\r\n\ /u\tExecuta com privilégios elevados.\r\n\ /v\tImprime o arquivo imediatamente e fecha.\r\n\ /vd\tImprime o arquivo (abre o diálogo de impressão).\r\n\ -/y\tCAMINHO do ambiente de pesquisa em caso de nome de\r\n\tarquivo relativo.\r\n\ -/z\tPular próximo (utilizável para substituição de Bloco de Notas\r\n\tcom base no registro).\r\n\r\n\ +/y\tCAMINHO do ambiente de pesquisa em caso de nome de tarquivo relativo.\r\n\ +/z\tPular próximo (utilizável para substituição de Bloco de Notas com base \r\n\tno registro).\r\n\r\n\ Exemplos:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ \t... Abre um novo arquivo: ""Test.txt"" Encoding=UTF-8-BOM, EoL=CRLF.\r\n\ diff --git a/language/np3_pt_pt/dialogs_pt_pt.rc b/language/np3_pt_pt/dialogs_pt_pt.rc index f40f06ff7..9fcc4b947 100644 --- a/language/np3_pt_pt/dialogs_pt_pt.rc +++ b/language/np3_pt_pt/dialogs_pt_pt.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 320, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Ajuda da linha de comandos" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,259,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,298,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_pt_pt/lexer_pt_pt.rc b/language/np3_pt_pt/lexer_pt_pt.rc index c4e2e361a..722ac36cd 100644 --- a/language/np3_pt_pt/lexer_pt_pt.rc +++ b/language/np3_pt_pt/lexer_pt_pt.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_pt_pt/strings_pt_pt.rc b/language/np3_pt_pt/strings_pt_pt.rc index ada54f2ac..757f104a7 100644 --- a/language/np3_pt_pt/strings_pt_pt.rc +++ b/language/np3_pt_pt/strings_pt_pt.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "Foram substituídas %s ocorrência(s) do padrão de procura especificado." IDS_MUI_ASK_ENCODING "A alteração da codificação do ficheiro de uma para outra, pode substituir texto não suportado com caracteres padrão e será limpo o histórico de anulações. Continuar?" IDS_MUI_ASK_ENCODING2 "Está prestes a alterar a codificação de um ficheiro vazio. Tenha em atenção de que isto irá limpar o histórico de anulações e que não pode ser sincronizado com a nova codificação. Continuar?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" é só de leitura. Guardar noutro ficheiro?" IDS_MUI_FILECHANGENOTIFY "O ficheiro actual foi modificado por um programa externo. Recarregar?" @@ -304,7 +305,7 @@ Opções:\r\n\ ...\tModo fim de linha (/crlf, /cr, /lf).\r\n\ /e\tCodificação do ficheiro de origem.\r\n\ /g\tSalta para posição indicada (/g -1 fim do ficheiro).\r\n\ -/m\tCorresponde ao texto especificado (/m- último, /mr regex,\r\n\t/mb backslash).\r\n\ +/m\tCorresponde ao texto especificado (/m- último, /mr regex, /mb backslash).\r\n\ /l\tAuto-recarrega ficheiros modificados.\r\n\ /q\tForça a criação de novos ficheiros sem perguntar.\r\n\ /s\tSelecciona esquema de sintaxe especificado.\r\n\ @@ -315,8 +316,8 @@ Opções:\r\n\ /b\tAbre novo quadro de colagem para recolher entradas da área \r\n\tde transferência.\r\n\ /n\tAbre sempre uma nova janela (/ns instância de único ficheiro).\r\n\ /r\tReutiliza a janela (/rs instância de único ficheiro).\r\n\ -/p\tDefine tamanho e posição da janela (/p0, /ps, /pf,l,t,r,b,m) ou /p\r\n\ -\t,,,[,,] [todos inteiros].\r\n\ +/p\tDefine tamanho e posição da janela (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tou /p ,,,[,,] [todos \r\n\tinteiros].\r\n\ /t\tDefine título da janela.\r\n\ /i\tInicia como ícone na área de notificação.\r\n\ /o\tMantém a janela sempre visível.\r\n\ @@ -328,7 +329,7 @@ Opções:\r\n\ /z\tIgnora seguinte (utilizável para substituição do Notepad com base \r\n\tno registro).\r\n\r\n\ Exemplos:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ - \t... Abre um novo ficheiro: ""Test.txt"" Codificação=UTF-8-BOM,\r\n\tEoL=CRLF.\r\n\ + \t... Abre um novo ficheiro: ""Test.txt"" Codificação=UTF-8-BOM, EoL=CRLF.\r\n\ Notepad3 /v d:\\temp\\Test.txt\r\n\ \t... Imprime o ficheiro: ""Test.txt"" imediatamente.\ " diff --git a/language/np3_ru_ru/dialogs_ru_ru.rc b/language/np3_ru_ru/dialogs_ru_ru.rc index 59e35e304..8039d0b7c 100644 --- a/language/np3_ru_ru/dialogs_ru_ru.rc +++ b/language/np3_ru_ru/dialogs_ru_ru.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 310, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Параметры командной строки" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,249,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,288,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 313, 142 diff --git a/language/np3_ru_ru/lexer_ru_ru.rc b/language/np3_ru_ru/lexer_ru_ru.rc index e92160803..61009de94 100644 --- a/language/np3_ru_ru/lexer_ru_ru.rc +++ b/language/np3_ru_ru/lexer_ru_ru.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_ru_ru/strings_ru_ru.rc b/language/np3_ru_ru/strings_ru_ru.rc index 181954924..57554ea22 100644 --- a/language/np3_ru_ru/strings_ru_ru.rc +++ b/language/np3_ru_ru/strings_ru_ru.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "Заменено вхождений указанного шаблона поиска: %s." IDS_MUI_ASK_ENCODING "Переключение кодировки файла с одной на другую может заменить неподдерживаемый текст заполнителями, а история отмены будет очищена. Все равно продолжить?" IDS_MUI_ASK_ENCODING2 "Вы собираетесь изменить кодировку пустого файла. Обратите внимание, что это очистит историю отмены, поскольку она не может быть синхронизирована с новой кодировкой. Все равно продолжить?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE "«%s» только для чтения. Сохранить в другой файл?" IDS_MUI_FILECHANGENOTIFY "Этот файл был изменен внешней программой. Переоткрыть его?" @@ -315,8 +316,8 @@ Notepad3 [/?] [...[Кодировка]] [...[Окончания строк]] [/e /b\tОткрыть новое окно для сбора изменений буфера обмена.\r\n\ /n\tВсегда открывать новое окно (/ns один экземпляр файла).\r\n\ /r\tПереиспользовать окно (/rs один экземпляр файла).\r\n\ -/p\tЗадать положение и размер окна (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tили /p ,,,[,,] [целые числа].\r\n\ +/p\tЗадать положение и размер окна (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tили /p ,,,[,,] [целые числа].\r\n\ /t\tЗадать заголовок окна.\r\n\ /i\tЗапустить иконкой в области уведомлений.\r\n\ /o\tПоверх других окон.\r\n\ diff --git a/language/np3_sk_sk/dialogs_sk_sk.rc b/language/np3_sk_sk/dialogs_sk_sk.rc index 65f62af68..7bfd69486 100644 --- a/language/np3_sk_sk/dialogs_sk_sk.rc +++ b/language/np3_sk_sk/dialogs_sk_sk.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 320, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Nápoveda príkazového riadka" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,259,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,298,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_sk_sk/lexer_sk_sk.rc b/language/np3_sk_sk/lexer_sk_sk.rc index 284270d33..7d1edb73b 100644 --- a/language/np3_sk_sk/lexer_sk_sk.rc +++ b/language/np3_sk_sk/lexer_sk_sk.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_sk_sk/strings_sk_sk.rc b/language/np3_sk_sk/strings_sk_sk.rc index db419f38c..927c6c17b 100644 --- a/language/np3_sk_sk/strings_sk_sk.rc +++ b/language/np3_sk_sk/strings_sk_sk.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s výskytov zadaného vyhľadávania bolo nahradených." IDS_MUI_ASK_ENCODING "Prepínanie kódovania súboru z jedného na iné môže spôsobiť, že nepodporované znaky budú nahradené predvolenými znakmi a história spätných krokov sa vymaže. Chcete pokračovať?" IDS_MUI_ASK_ENCODING2 "Chystáte sa zmeniť kódovanie prázdneho súboru. Upozorňujeme, že týmto sa vymaže história spätných krokov, pretože sa nedá synchronizovať s novým kódovaním. Pokračovať?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" je iba na čítanie. Uložiť súbor pod iným názvom?" IDS_MUI_FILECHANGENOTIFY "Aktuálny súbor bol upravený externým programom. Znovu ho načítať?" @@ -295,7 +296,7 @@ Použitie:\r\n\ Notepad3 [/?] [...[Kódovanie]] [...[Režim ukončenia riadku]] [/e] [/g] [/m] [/l]\r\n\ \t[/q] [/s] [/d] [/h] [/x] [/c] [/b] [/n] [/r| [/p] [/t] [/i] [/o]\r\n\ \t[/f] [/u] [/v] [/vd] [/y] [/z] [[disk:][cesta]názov súboru[...]]\r\n\r\n\ -súbor\tMusí to byť posledný argument, v predvolenom nastavení nie sú\r\n\tmedzery.\r\n\ +súbor\tMusí to byť posledný argument, v predvolenom nastavení nie sú medzery.\r\n\ +\tAkceptuje viac argumentov súborov (s medzerami).\r\n\ -\tAkceptuje argument jedného súboru (bez medzier).\r\n\r\n\ Možnosti:\r\n\ @@ -315,8 +316,8 @@ Možnosti:\r\n\ /b\tOtvorenie nového panela na vkladanie a zber záznamov zo schránky.\r\n\ /n\tVždy otvoriť nové okno (/ns inštancia jedného súboru).\r\n\ /r\tOpätovné použitie okna (/rs inštancia jedného súboru).\r\n\ -/p\tNastavenie polohy a veľkosti okna (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\talebo /p ,,<šírka>,[,,] [všetky čísla celé].\r\n\ +/p\tNastavenie polohy a veľkosti okna (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\talebo /p ,,<šírka>,[,,] [všetky čísla \r\n\tcelé].\r\n\ /t\tNastavenie titulku okna.\r\n\ /i\tZačať ako ikona na paneli úloh.\r\n\ /o\tPonechanie okna vždy na vrchu.\r\n\ @@ -325,7 +326,7 @@ Možnosti:\r\n\ /v\tOkamžité vytlačenie súboru a ukončenie.\r\n\ /vd\tTlač súboru cez dialógové okno tlačiarne.\r\n\ /y\tVyhľadanie prostredia cesty v prípade relatívneho názvu súboru.\r\n\ -/z\tPreskočiť ďalej (použiteľné pri zámene Poznámkového bloku\r\n\tWindows pomocou registrov).\r\n\r\n\ +/z\tPreskočiť ďalej (použiteľné pri zámene Poznámkového bloku Windows \r\n\tpomocou registrov).\r\n\r\n\ Príklady:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ \t... Otvoriť nový súbor: ""Test.txt"" Encoding=UTF-8-BOM, EoL=CRLF.\r\n\ diff --git a/language/np3_sv_se/dialogs_sv_se.rc b/language/np3_sv_se/dialogs_sv_se.rc index 4c625aa4c..725d374d1 100644 --- a/language/np3_sv_se/dialogs_sv_se.rc +++ b/language/np3_sv_se/dialogs_sv_se.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 310, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Hjälp för kommandorad" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,249,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,288,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 273, 142 diff --git a/language/np3_sv_se/lexer_sv_se.rc b/language/np3_sv_se/lexer_sv_se.rc index 5c80503fd..e2c834ea7 100644 --- a/language/np3_sv_se/lexer_sv_se.rc +++ b/language/np3_sv_se/lexer_sv_se.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symboloperatör" IDS_LEX_STR_63388 "Sträng EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_sv_se/strings_sv_se.rc b/language/np3_sv_se/strings_sv_se.rc index d9ebcfcac..a0171e89b 100644 --- a/language/np3_sv_se/strings_sv_se.rc +++ b/language/np3_sv_se/strings_sv_se.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s träff(ar) för angivet sökmönster ersatta." IDS_MUI_ASK_ENCODING "Att byta teckenkodning från en kodning till en annan kommer att ersätta tecken som inte stöds med standardtecken och ångerhistoriken kommer att rensas. Vill du fortsätta?" IDS_MUI_ASK_ENCODING2 "Du kommer att ändra teckenkodning i en tom fil. Notera att detta kommer att rensa ångerhistoriken. Vill du fortsätta?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" är inte skrivbar. Vill du spara till en annan fil?" IDS_MUI_FILECHANGENOTIFY "Aktuell fil har modifierats av ett externt program. Vill du ladda om?" @@ -315,8 +316,8 @@ Tillval:\r\n\ /b\tÖppna urklippsbordet för att samla alla urklipp.\r\n\ /n\tÖppna alltid nytt fönster (/ns enkel filinstans).\r\n\ /r\tÅteranvänd fönster (/rs enkel filinstans).\r\n\ -/p\tAnge fönsterposition och storlek (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\teller /p ,,,[,,] [alla heltal].\r\n\ +/p\tAnge fönsterposition och storlek (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\teller /p ,,,[,,] [alla heltal].\r\n\ /t\tAnge fönstertitel.\r\n\ /i\tStarta som ikon i verktygsfältet.\r\n\ /o\tVisa alltid fönstret överst.\r\n\ @@ -325,7 +326,7 @@ Tillval:\r\n\ /v\tSpara fil och avsluta.\r\n\ /vd\tSkriv ut fil (öppna skrivardialogen).\r\n\ /y\tSök miljövariable vid relativt filnamn.\r\n\ -/z\tHoppa över nästa (användbart för registerbaserad\r\n\tnotepad-ersättning).\r\n\r\n\ +/z\tHoppa över nästa (användbart för registerbaserad notepad-ersättning).\r\n\r\n\ Exempel:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Test.txt\r\n\ \t... Öppna ny fil: ""Test.txt"" Encoding=UTF-8-BOM, EoL=CRLF.\r\n\ diff --git a/language/np3_tr_tr/dialogs_tr_tr.rc b/language/np3_tr_tr/dialogs_tr_tr.rc index 566fac6ab..2d9e122f8 100644 --- a/language/np3_tr_tr/dialogs_tr_tr.rc +++ b/language/np3_tr_tr/dialogs_tr_tr.rc @@ -74,13 +74,13 @@ BEGIN CONTROL "",IDC_RICHEDITABOUT,RICHEDIT_CONTROL_VER,WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | RICHEDTCTRL_ADDSTYLE,20,90,360,170, ES_EX_ZOOMABLE END -IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 300, 210 +IDD_MUI_CMDLINEHELP DIALOGEX 0, 0, 310, 210 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Komut satırı yardımı" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "Tamam",IDOK,239,187,55,16 - EDITTEXT IDC_CMDLINEHELP,15,7,278,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "Tamam",IDOK,249,187,55,16 + EDITTEXT IDC_CMDLINEHELP,15,7,288,176,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL END IDD_MUI_FIND DIALOGEX 0, 0, 285, 142 diff --git a/language/np3_tr_tr/lexer_tr_tr.rc b/language/np3_tr_tr/lexer_tr_tr.rc index e1180aade..a9e951a9b 100644 --- a/language/np3_tr_tr/lexer_tr_tr.rc +++ b/language/np3_tr_tr/lexer_tr_tr.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Simge işlemi" IDS_LEX_STR_63388 "Dizge satır sonu" IDS_LEX_STR_63397 "Ters tik" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_tr_tr/strings_tr_tr.rc b/language/np3_tr_tr/strings_tr_tr.rc index ea7da5f00..739eed22c 100644 --- a/language/np3_tr_tr/strings_tr_tr.rc +++ b/language/np3_tr_tr/strings_tr_tr.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "Belirtilen aramaya uygun %s eşleşme bulundu." IDS_MUI_ASK_ENCODING "Dosya kodlamasını değiştirmek desteklenmeyen karakterlerin varsayılanlar ile değiştirilmesine yol açar ve geri alma geçmişini temizler. Devam etmek istiyor musunuz?" IDS_MUI_ASK_ENCODING2 "Boş bir dosyanın kodlamasını değiştirmek üzeresiniz. Yeni kodlama ile eşitlenemeyeceğinden bu işlemin geri alma geçmişini sileceğini unutmayın. Devam etmek istiyor musunuz?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" salt okunur. Başka bir dosyaya kaydetmek ister misiniz?" IDS_MUI_FILECHANGENOTIFY "Geçerli dosya başka bir uygulama tarafından değiştirilmiş Yeniden yüklemek ister misiniz?" @@ -315,8 +316,8 @@ Seçenekler:\r\n\ /b\tPano kayıtlarını derlemek için yeni yapıştırma panosu açar.\r\n\ /n\tHer zaman yeni pencerede açar (/ns tek dosya kopyası).\r\n\ /r\tPencereyi yeniden kullanır (/rs tek dosya kopyası).\r\n\ -/p\tPencere konumunu ve boyutunu ayarlar (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tor /p ,,,[,,] [tümü tam sayı].\r\n\ +/p\tPencere konumunu ve boyutunu ayarlar (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tor /p ,,,[,,] [tümü tam sayı].\r\n\ /t\tPencere başlığını ayarlar.\r\n\ /i\tSistem tepsisinde başlatır.\r\n\ /o\tPencereyi üste sabitler.\r\n\ @@ -325,7 +326,7 @@ Seçenekler:\r\n\ /v\tDosyayı hemen yazdırır ve çıkar.\r\n\ /vd\tDosyayı yazdırır (yazıcı penceresini açar).\r\n\ /y\tGöreli dosya adı durumuna karşı PATH ortam değişkeninde arar.\r\n\ -/z\tSonrakine geçer (kayıt defteri temelli Notepad değişikliği\r\n\tiçin kullanışlı).\r\n\r\n\ +/z\tSonrakine geçer (kayıt defteri temelli Notepad değişikliği için kullanışlı).\r\n\r\n\ Örnekler:\r\n\ Notepad3 /utf8sig /crlf d:\\temp\\Deneme.txt\r\n\ \t... Yeni bir dosya açar: ""Deneme.txt"" Encoding=UTF-8-BOM, EoL=CRLF.\r\n\ diff --git a/language/np3_vi_vn/lexer_vi_vn.rc b/language/np3_vi_vn/lexer_vi_vn.rc index 52c4d5010..1148a31fc 100644 --- a/language/np3_vi_vn/lexer_vi_vn.rc +++ b/language/np3_vi_vn/lexer_vi_vn.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_vi_vn/strings_vi_vn.rc b/language/np3_vi_vn/strings_vi_vn.rc index 13825b094..0ffa68db9 100644 --- a/language/np3_vi_vn/strings_vi_vn.rc +++ b/language/np3_vi_vn/strings_vi_vn.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s occurrence(s) of specified search pattern replaced." IDS_MUI_ASK_ENCODING "Switching the file encoding from one encoding to another may replace unsupported text with default characters, and the undo history will be cleared. Continue?" IDS_MUI_ASK_ENCODING2 "You are about to change the encoding of an empty file. Note that this will clear the undo history, as it can't be synchronised with the new encoding. Continue?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" is read only. Save to a different file?" IDS_MUI_FILECHANGENOTIFY "The current file has been modified by an external program. Reload?" @@ -315,8 +316,8 @@ Options:\r\n\ /b\tOpen new paste board to collect clipboard entries.\r\n\ /n\tAlways open a new window (/ns single file instance).\r\n\ /r\tReuse window (/rs single file instance).\r\n\ -/p\tSet window position and size (/p0, /ps, /pf,l,t,r,b,m)\r\n\ -\tor /p ,,,[,,] [all integers].\r\n\ +/p\tSet window position and size (/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\tor /p ,,,[,,] [all integers].\r\n\ /t\tSet window title.\r\n\ /i\tStart as tray icon.\r\n\ /o\tKeep window on top.\r\n\ diff --git a/language/np3_zh_cn/lexer_zh_cn.rc b/language/np3_zh_cn/lexer_zh_cn.rc index 5a556910e..1a9e22f5e 100644 --- a/language/np3_zh_cn/lexer_zh_cn.rc +++ b/language/np3_zh_cn/lexer_zh_cn.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_zh_cn/strings_zh_cn.rc b/language/np3_zh_cn/strings_zh_cn.rc index e230b91da..cd8f0cdfd 100644 --- a/language/np3_zh_cn/strings_zh_cn.rc +++ b/language/np3_zh_cn/strings_zh_cn.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "替换了 %s 个匹配项。" IDS_MUI_ASK_ENCODING "切换文件编码可能导致部分无法表示的字符被替换为其它字符,并且该操作会清空撤销历史。是否继续?" IDS_MUI_ASK_ENCODING2 "切换文件编码会清空撤销历史。是否继续?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE "“%s”是只读的。是否尝试使用其它名字保存?" IDS_MUI_FILECHANGENOTIFY "当前文件已被其它程序修改。是否重新加载?" @@ -315,8 +316,8 @@ Notepad3 [/?] [...[编码]] [...[换行符模式]] [/e] [/g] [/m] [/l]\r\n\ /b\t打开剪贴板收集窗口(自动粘贴加入到剪贴板中的内容)。\r\n\ /n\t总是打开新窗口(/ns 对于每个文件只允许打开一个实例)。\r\n\ /r\t重用已存在的窗口(/rs 对于每个文件只允许打开一个实例)。\r\n\ -/p\t设置窗口位置和大小(/p0, /ps, /pf,左,上,宽,高,最大化)\r\n\ -\t或 /p <左>,<上>,<宽>,<高>[,,<最大化>] [均为整数]。\r\n\ +/p\t设置窗口位置和大小(/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\t或 /p <左>,<上>,<宽>,<高>[,,<最大化>] [均为整数]。\r\n\ /t\t设置窗口标题。\r\n\ /i\t以托盘图标状态启动。\r\n\ /o\t窗口置顶。\r\n\ diff --git a/language/np3_zh_tw/lexer_zh_tw.rc b/language/np3_zh_tw/lexer_zh_tw.rc index accae2d36..9f6d2fdeb 100644 --- a/language/np3_zh_tw/lexer_zh_tw.rc +++ b/language/np3_zh_tw/lexer_zh_tw.rc @@ -496,6 +496,7 @@ BEGIN IDS_LEX_STR_63387 "Symbol Operator" IDS_LEX_STR_63388 "String EOL" IDS_LEX_STR_63397 "Backticks" + IDS_LEX_STR_63398 "GUID String" END STRINGTABLE diff --git a/language/np3_zh_tw/strings_zh_tw.rc b/language/np3_zh_tw/strings_zh_tw.rc index 1558a9d1e..416841f08 100644 --- a/language/np3_zh_tw/strings_zh_tw.rc +++ b/language/np3_zh_tw/strings_zh_tw.rc @@ -174,6 +174,7 @@ BEGIN IDS_MUI_REPLCOUNT "%s 次出現的指定搜索模式已被替換。" IDS_MUI_ASK_ENCODING "切換檔案編碼可能導致部分無法表示的字元被替換為其它字元,並且該操作會清空取消歷程記錄。是否繼續?" IDS_MUI_ASK_ENCODING2 "切換檔案編碼會清空取消歷程記錄。是否繼續?" + IDS_MUI_ASK_CLEAR_UNDO "This operation will clear the undo history. Continue?" IDS_MUI_READONLY_SAVE """%s"" 是唯讀。是否嘗試使用其它名字儲存?" IDS_MUI_FILECHANGENOTIFY "目前檔案已被其它程式修改。是否重新載入?" @@ -315,8 +316,8 @@ Notepad3 [/?] [...[編碼]] [...[分行符號模式]] [/e] [/g] [/m] [/l]\r\n\ /b\t開啟剪貼簿收集視窗(自動貼上加入到剪貼簿中的內容)。\r\n\ /n\t總是開啟新視窗(/ns 對於每個檔案只允許開啟一個實例)。\r\n\ /r\t重新使用已存在的視窗(/rs 對於每個檔案只允許開啟一個實例)。\r\n\ -/p\t設定視窗位置和大小(/p0, /ps, /pf,左,上,寬,高,最大化)\r\n\ -\t或 /p <左>,<上>,<寬>,<高>[,,<最大化>] [均為整數]。\r\n\ +/p\t設定視窗位置和大小(/p0,/ps,/pd,f,l,t,r,b,m)\r\n\ +\t或 /p <左>,<上>,<寬>,<高>[,,<最大化>] [均為整數]。\r\n\ /t\t設定視窗標題。\r\n\ /i\t以系統匣圖示狀態啟動。\r\n\ /o\t視窗置頂。\r\n\ diff --git a/lexilla/Lexilla.vcxproj b/lexilla/Lexilla.vcxproj index 707b43380..38d512edd 100644 --- a/lexilla/Lexilla.vcxproj +++ b/lexilla/Lexilla.vcxproj @@ -72,6 +72,7 @@ + @@ -95,7 +96,6 @@ - diff --git a/lexilla/Lexilla.vcxproj.filters b/lexilla/Lexilla.vcxproj.filters index d6b568044..aa27fac13 100644 --- a/lexilla/Lexilla.vcxproj.filters +++ b/lexilla/Lexilla.vcxproj.filters @@ -272,8 +272,8 @@ lexers - - lexers_x + + lexers diff --git a/lexilla/lexers/LexMarkdown.cxx b/lexilla/lexers/LexMarkdown.cxx new file mode 100644 index 000000000..ac2b9f9ec --- /dev/null +++ b/lexilla/lexers/LexMarkdown.cxx @@ -0,0 +1,486 @@ +/****************************************************************** + * LexMarkdown.cxx + * + * A simple Markdown lexer for scintilla. + * + * Includes highlighting for some extra features from the + * Pandoc implementation; strikeout, using '#.' as a default + * ordered list item marker, and delimited code blocks. + * + * Limitations: + * + * Standard indented code blocks are not highlighted at all, + * as it would conflict with other indentation schemes. Use + * delimited code blocks for blanket highlighting of an + * entire code block. Embedded HTML is not highlighted either. + * Blanket HTML highlighting has issues, because some Markdown + * implementations allow Markdown markup inside of the HTML. Also, + * there is a following blank line issue that can't be ignored, + * explained in the next paragraph. Embedded HTML and code + * blocks would be better supported with language specific + * highlighting. + * + * The highlighting aims to accurately reflect correct syntax, + * but a few restrictions are relaxed. Delimited code blocks are + * highlighted, even if the line following the code block is not blank. + * Requiring a blank line after a block, breaks the highlighting + * in certain cases, because of the way Scintilla ends up calling + * the lexer. + * + * Written by Jon Strait - jstrait@moonloop.net + * + * The License.txt file describes the conditions under which this + * software may be distributed. + * + *****************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + +using namespace Lexilla; + +namespace { + +constexpr bool IsNewline(const int ch) { + // sc.GetRelative(i) returns '\0' if out of range + return (ch == '\n' || ch == '\r' || ch == '\0'); +} + +} + +// True if can follow ch down to the end with possibly trailing whitespace +// Does not set the state SCE_MARKDOWN_LINE_BEGIN as to allow further processing +static bool FollowToLineEnd(const int ch, const int state, const Sci_PositionU endPos, StyleContext &sc) { + Sci_Position i = 0; + while (sc.GetRelative(++i) == ch) + ; + // Skip over whitespace + while (IsASpaceOrTab(sc.GetRelative(i)) && sc.currentPos + i < endPos) + ++i; + if (IsNewline(sc.GetRelative(i)) || sc.currentPos + i == endPos) { + sc.SetState(state); + sc.Forward(i); + return true; + } + else return false; +} + +// Set the state on text section from current to length characters, +// then set the rest until the newline to default, except for any characters matching token +static void SetStateAndZoom(const int state, const Sci_Position length, const int token, StyleContext &sc) { + sc.SetState(state); + sc.Forward(length); + sc.SetState(SCE_MARKDOWN_DEFAULT); + sc.Forward(); + bool started = false; + while (sc.More() && !IsNewline(sc.ch)) { + if (sc.ch == token && !started) { + sc.SetState(state); + started = true; + } + else if (sc.ch != token) { + sc.SetState(SCE_MARKDOWN_DEFAULT); + started = false; + } + sc.Forward(); + } + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); +} + +// Does the previous line have more than spaces and tabs? +static bool HasPrevLineContent(StyleContext &sc) { + Sci_Position i = 0; + // Go back to the previous newline + while ((--i + (Sci_Position)sc.currentPos) >= 0 && !IsNewline(sc.GetRelative(i))) + ; + while ((--i + (Sci_Position)sc.currentPos) >= 0) { + const int ch = sc.GetRelative(i); + if (ch == '\n') + break; + if (!((ch == '\r' || IsASpaceOrTab(ch)))) + return true; + } + return false; +} + +static bool AtTermStart(StyleContext &sc) { + return sc.currentPos == 0 || sc.chPrev == 0 || isspacechar(sc.chPrev); +} + +static bool IsCompleteStyleRegion(StyleContext &sc, const char *token) { + bool found = false; + const size_t start = strlen(token); + Sci_Position i = static_cast(start); + while (!IsNewline(sc.GetRelative(i))) { + // make sure an empty pair of single-char tokens doesn't match + // with a longer token: {*}{*} != {**} + if (sc.GetRelative(i) == *token && sc.GetRelative(i - 1) != *token) { + found = start > 1U ? sc.GetRelative(i + 1) == token[1] : true; + break; + } + i++; + } + return AtTermStart(sc) && found; +} + +static bool IsValidHrule(const Sci_PositionU endPos, StyleContext &sc) { + int count = 1; + Sci_Position i = 0; + for (;;) { + ++i; + int c = sc.GetRelative(i); + if (c == sc.ch) + ++count; + // hit a terminating character + else if (!IsASpaceOrTab(c) || sc.currentPos + i == endPos) { + // Are we a valid HRULE + if ((IsNewline(c) || sc.currentPos + i == endPos) && + count >= 3 && !HasPrevLineContent(sc)) { + sc.SetState(SCE_MARKDOWN_HRULE); + sc.Forward(i); + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + return true; + } + else { + sc.SetState(SCE_MARKDOWN_DEFAULT); + return false; + } + } + } +} + +static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, + WordList **, Accessor &styler) { + Sci_PositionU endPos = startPos + length; + int precharCount = 0; + bool isLinkNameDetecting = false; + // Don't advance on a new loop iteration and retry at the same position. + // Useful in the corner case of having to start at the beginning file position + // in the default state. + bool freezeCursor = false; + + // property lexer.markdown.header.eolfill + // Set to 1 to highlight all ATX header text. + bool headerEOLFill = styler.GetPropertyInt("lexer.markdown.header.eolfill", 0) == 1; + + StyleContext sc(startPos, static_cast(length), initStyle, styler); + + while (sc.More()) { + // Skip past escaped characters + if (sc.ch == '\\') { + sc.Forward(); + continue; + } + + // A blockquotes resets the line semantics + if (sc.state == SCE_MARKDOWN_BLOCKQUOTE) + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + + // Conditional state-based actions + if (sc.state == SCE_MARKDOWN_CODE2) { + if (sc.Match("``")) { + const int closingSpan = (sc.GetRelative(2) == '`') ? 3 : 2; + sc.Forward(closingSpan); + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + } + else if (sc.state == SCE_MARKDOWN_CODE) { + if (sc.ch == '`' && sc.chPrev != ' ') + sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); + } + /* De-activated because it gets in the way of other valid indentation + * schemes, for example multiple paragraphs inside a list item. + // Code block + else if (sc.state == SCE_MARKDOWN_CODEBK) { + bool d = true; + if (IsNewline(sc.ch)) { + if (sc.chNext != '\t') { + for (int c = 1; c < 5; ++c) { + if (sc.GetRelative(c) != ' ') + d = false; + } + } + } + else if (sc.atLineStart) { + if (sc.ch != '\t' ) { + for (int i = 0; i < 4; ++i) { + if (sc.GetRelative(i) != ' ') + d = false; + } + } + } + if (!d) + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + } + */ + // Strong + else if (sc.state == SCE_MARKDOWN_STRONG1) { + if ((sc.Match("**") && sc.chPrev != ' ') || IsNewline(sc.GetRelative(2))) { + sc.Forward(2); + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + } + else if (sc.state == SCE_MARKDOWN_STRONG2) { + if ((sc.Match("__") && sc.chPrev != ' ') || IsNewline(sc.GetRelative(2))) { + sc.Forward(2); + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + } + // Emphasis + else if (sc.state == SCE_MARKDOWN_EM1) { + if ((sc.ch == '*' && sc.chPrev != ' ') || IsNewline(sc.chNext)) + sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); + } + else if (sc.state == SCE_MARKDOWN_EM2) { + if ((sc.ch == '_' && sc.chPrev != ' ') || IsNewline(sc.chNext)) + sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); + } + else if (sc.state == SCE_MARKDOWN_CODEBK) { + if (sc.atLineStart && sc.Match("~~~")) { + Sci_Position i = 1; + while (!IsNewline(sc.GetRelative(i)) && sc.currentPos + i < endPos) + i++; + sc.Forward(i); + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + } + else if (sc.state == SCE_MARKDOWN_STRIKEOUT) { + if ((sc.Match("~~") && sc.chPrev != ' ') || IsNewline(sc.GetRelative(2))) { + sc.Forward(2); + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + } + else if (sc.state == SCE_MARKDOWN_LINE_BEGIN) { + // Header + if (sc.Match("######")) { + if (headerEOLFill) + sc.SetState(SCE_MARKDOWN_HEADER6); + else + SetStateAndZoom(SCE_MARKDOWN_HEADER6, 6, '#', sc); + } + else if (sc.Match("#####")) { + if (headerEOLFill) + sc.SetState(SCE_MARKDOWN_HEADER5); + else + SetStateAndZoom(SCE_MARKDOWN_HEADER5, 5, '#', sc); + } + else if (sc.Match("####")) { + if (headerEOLFill) + sc.SetState(SCE_MARKDOWN_HEADER4); + else + SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc); + } + else if (sc.Match("###")) { + if (headerEOLFill) + sc.SetState(SCE_MARKDOWN_HEADER3); + else + SetStateAndZoom(SCE_MARKDOWN_HEADER3, 3, '#', sc); + } + else if (sc.Match("##")) { + if (headerEOLFill) + sc.SetState(SCE_MARKDOWN_HEADER2); + else + SetStateAndZoom(SCE_MARKDOWN_HEADER2, 2, '#', sc); + } + else if (sc.Match("#")) { + // Catch the special case of an unordered list + if (sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) { + precharCount = 0; + sc.SetState(SCE_MARKDOWN_PRECHAR); + } + else if (headerEOLFill) { + sc.SetState(SCE_MARKDOWN_HEADER1); + } + else + SetStateAndZoom(SCE_MARKDOWN_HEADER1, 1, '#', sc); + } + // Code block + else if (sc.Match("~~~")) { + if (!HasPrevLineContent(sc)) + sc.SetState(SCE_MARKDOWN_CODEBK); + else + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + else if (sc.ch == '=') { + if (HasPrevLineContent(sc) && FollowToLineEnd('=', SCE_MARKDOWN_HEADER1, endPos, sc)) { + if (!headerEOLFill) + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + } + else + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + else if (sc.ch == '-') { + if (HasPrevLineContent(sc) && FollowToLineEnd('-', SCE_MARKDOWN_HEADER2, endPos, sc)) { + if (!headerEOLFill) + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + } + else { + precharCount = 0; + sc.SetState(SCE_MARKDOWN_PRECHAR); + } + } + else if (IsNewline(sc.ch)) + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + else { + precharCount = 0; + sc.SetState(SCE_MARKDOWN_PRECHAR); + } + } + + // The header lasts until the newline + else if (sc.state == SCE_MARKDOWN_HEADER1 || sc.state == SCE_MARKDOWN_HEADER2 || + sc.state == SCE_MARKDOWN_HEADER3 || sc.state == SCE_MARKDOWN_HEADER4 || + sc.state == SCE_MARKDOWN_HEADER5 || sc.state == SCE_MARKDOWN_HEADER6) { + if (headerEOLFill) { + if (sc.atLineStart) { + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + freezeCursor = true; + } + } + else if (IsNewline(sc.ch)) + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + } + + // New state only within the initial whitespace + if (sc.state == SCE_MARKDOWN_PRECHAR) { + // Blockquote + if (sc.ch == '>' && precharCount < 5) + sc.SetState(SCE_MARKDOWN_BLOCKQUOTE); + /* + // Begin of code block + else if (!HasPrevLineContent(sc) && (sc.chPrev == '\t' || precharCount >= 4)) + sc.SetState(SCE_MARKDOWN_CODEBK); + */ + // HRule - Total of three or more hyphens, asterisks, or underscores + // on a line by themselves + else if ((sc.ch == '-' || sc.ch == '*' || sc.ch == '_') && IsValidHrule(endPos, sc)) + ; + // Unordered list + else if ((sc.ch == '-' || sc.ch == '*' || sc.ch == '+') && IsASpaceOrTab(sc.chNext)) { + sc.SetState(SCE_MARKDOWN_ULIST_ITEM); + sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); + } + // Ordered list + else if (IsADigit(sc.ch)) { + int digitCount = 0; + while (IsADigit(sc.GetRelative(++digitCount))) + ; + if (sc.GetRelative(digitCount) == '.' && + IsASpaceOrTab(sc.GetRelative(digitCount + 1))) { + sc.SetState(SCE_MARKDOWN_OLIST_ITEM); + sc.Forward(digitCount + 1); + sc.SetState(SCE_MARKDOWN_DEFAULT); + } else { + // a textual number at the margin should be plain text + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + } + // Alternate Ordered list + else if (sc.ch == '#' && sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) { + sc.SetState(SCE_MARKDOWN_OLIST_ITEM); + sc.Forward(2); + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + else if (sc.ch != ' ' || precharCount > 2) + sc.SetState(SCE_MARKDOWN_DEFAULT); + else + ++precharCount; + } + + // Any link + if (sc.state == SCE_MARKDOWN_LINK) { + if (sc.Match("](") && sc.GetRelative(-1) != '\\') { + sc.Forward(2); + isLinkNameDetecting = true; + } + else if (sc.Match("]:") && sc.GetRelative(-1) != '\\') { + sc.Forward(2); + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + else if (!isLinkNameDetecting && sc.ch == ']' && sc.GetRelative(-1) != '\\') { + sc.Forward(); + sc.SetState(SCE_MARKDOWN_DEFAULT); + } + else if (isLinkNameDetecting && sc.ch == ')' && sc.GetRelative(-1) != '\\') { + sc.Forward(); + sc.SetState(SCE_MARKDOWN_DEFAULT); + isLinkNameDetecting = false; + } + } + + // New state anywhere in doc + if (sc.state == SCE_MARKDOWN_DEFAULT) { + if (sc.atLineStart && sc.ch == '#') { + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + freezeCursor = true; + } + // Links and Images + if (sc.Match("![")) { + sc.SetState(SCE_MARKDOWN_LINK); + sc.Forward(1); + } + else if (sc.ch == '[' && sc.GetRelative(-1) != '\\') { + sc.SetState(SCE_MARKDOWN_LINK); + } + // Code - also a special case for alternate inside spacing + else if (sc.Match("``") && sc.GetRelative(3) != ' ' && AtTermStart(sc)) { + const int openingSpan = (sc.GetRelative(2) == '`') ? 2 : 1; + sc.SetState(SCE_MARKDOWN_CODE2); + sc.Forward(openingSpan); + } + else if (sc.ch == '`' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "`")) { + sc.SetState(SCE_MARKDOWN_CODE); + } + // Strong + else if (sc.Match("**") && sc.GetRelative(2) != ' ' && IsCompleteStyleRegion(sc, "**")) { + sc.SetState(SCE_MARKDOWN_STRONG1); + sc.Forward(); + } + else if (sc.Match("__") && sc.GetRelative(2) != ' ' && IsCompleteStyleRegion(sc, "__")) { + sc.SetState(SCE_MARKDOWN_STRONG2); + sc.Forward(); + } + // Emphasis + else if (sc.ch == '*' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "*")) { + sc.SetState(SCE_MARKDOWN_EM1); + } + else if (sc.ch == '_' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "_")) { + sc.SetState(SCE_MARKDOWN_EM2); + } + // Strikeout + else if (sc.Match("~~") && !(sc.GetRelative(2) == '~' || sc.GetRelative(2) == ' ') && + IsCompleteStyleRegion(sc, "~~")) { + sc.SetState(SCE_MARKDOWN_STRIKEOUT); + sc.Forward(); + } + // Beginning of line + else if (IsNewline(sc.ch)) { + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + } + } + // Advance if not holding back the cursor for this iteration. + if (!freezeCursor) + sc.Forward(); + freezeCursor = false; + } + sc.Complete(); +} + +LexerModule lmMarkdown(SCLEX_MARKDOWN, ColorizeMarkdownDoc, "markdown"); diff --git a/lexilla/lexers_x/LexMarkdown.cxx b/lexilla/lexers_x/homebrew/LexMarkdown.cxx similarity index 99% rename from lexilla/lexers_x/LexMarkdown.cxx rename to lexilla/lexers_x/homebrew/LexMarkdown.cxx index 38c398e1e..9daee9913 100644 --- a/lexilla/lexers_x/LexMarkdown.cxx +++ b/lexilla/lexers_x/homebrew/LexMarkdown.cxx @@ -277,7 +277,7 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int freezeCursor = true; } else if (sc.Match("####")) { - SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc); + SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc); freezeCursor = true; } else if (sc.Match("###")) { diff --git a/lexilla/src/deps.mak b/lexilla/src/deps.mak index 4f7d228b4..6282b581f 100644 --- a/lexilla/src/deps.mak +++ b/lexilla/src/deps.mak @@ -364,6 +364,18 @@ $(DIR_O)/LexMake.o: \ ../lexlib/StyleContext.h \ ../lexlib/CharacterSet.h \ ../lexlib/LexerModule.h +$(DIR_O)/LexMarkdown.o: \ + ../lexers/LexMarkdown.cxx \ + ../../scintilla/include/ILexer.h \ + ../../scintilla/include/Sci_Position.h \ + ../../scintilla/include/Scintilla.h \ + ../include/SciLexer.h \ + ../lexlib/WordList.h \ + ../lexlib/LexAccessor.h \ + ../lexlib/Accessor.h \ + ../lexlib/StyleContext.h \ + ../lexlib/CharacterSet.h \ + ../lexlib/LexerModule.h $(DIR_O)/LexMatlab.o: \ ../lexers/LexMatlab.cxx \ ../../scintilla/include/ILexer.h \ @@ -681,19 +693,6 @@ $(DIR_O)/LexKotlin.o: \ ../include/SciLexer.h \ ../lexers_x/StringUtils.h \ ../lexers_x/LexerUtils.h -$(DIR_O)/LexMarkdown.o: \ - ../lexers_x/LexMarkdown.cxx \ - ../../scintilla/include/ILexer.h \ - ../../scintilla/include/Sci_Position.h \ - ../../scintilla/include/Scintilla.h \ - ../include/SciLexer.h \ - ../lexlib/WordList.h \ - ../lexlib/LexAccessor.h \ - ../lexlib/Accessor.h \ - ../lexlib/StyleContext.h \ - ../lexers_x/CharSetX.h \ - ../lexlib/CharacterSet.h \ - ../lexlib/LexerModule.h $(DIR_O)/LexPython.o: \ ../lexers_x/LexPython.cxx \ ../../scintilla/include/ILexer.h \ diff --git a/lexilla/src/lexilla.mak b/lexilla/src/lexilla.mak index 48d2ecacf..16bc391c3 100644 --- a/lexilla/src/lexilla.mak +++ b/lexilla/src/lexilla.mak @@ -94,6 +94,7 @@ LEX_OBJS=\ $(DIR_O)\LexLaTeX.obj \ $(DIR_O)\LexLua.obj \ $(DIR_O)\LexMake.obj \ + $(DIR_O)\LexMarkdown.obj \ $(DIR_O)\LexMatlab.obj \ $(DIR_O)\LexNim.obj \ $(DIR_O)\LexNsis.obj \ @@ -117,7 +118,6 @@ LEX_OBJS=\ $(DIR_O)\LexerUtils.obj \ $(DIR_O)\LexJSON.obj \ $(DIR_O)\LexKotlin.obj \ - $(DIR_O)\LexMarkdown.obj \ $(DIR_O)\LexPython.obj \ $(DIR_O)\LexTOML.obj \ diff --git a/lexilla/src/nmdeps.mak b/lexilla/src/nmdeps.mak index 1dd98ae85..0e578d8d9 100644 --- a/lexilla/src/nmdeps.mak +++ b/lexilla/src/nmdeps.mak @@ -364,6 +364,18 @@ $(DIR_O)/LexMake.obj: \ ../lexlib/StyleContext.h \ ../lexlib/CharacterSet.h \ ../lexlib/LexerModule.h +$(DIR_O)/LexMarkdown.obj: \ + ../lexers/LexMarkdown.cxx \ + ../../scintilla/include/ILexer.h \ + ../../scintilla/include/Sci_Position.h \ + ../../scintilla/include/Scintilla.h \ + ../include/SciLexer.h \ + ../lexlib/WordList.h \ + ../lexlib/LexAccessor.h \ + ../lexlib/Accessor.h \ + ../lexlib/StyleContext.h \ + ../lexlib/CharacterSet.h \ + ../lexlib/LexerModule.h $(DIR_O)/LexMatlab.obj: \ ../lexers/LexMatlab.cxx \ ../../scintilla/include/ILexer.h \ @@ -681,19 +693,6 @@ $(DIR_O)/LexKotlin.obj: \ ../include/SciLexer.h \ ../lexers_x/StringUtils.h \ ../lexers_x/LexerUtils.h -$(DIR_O)/LexMarkdown.obj: \ - ../lexers_x/LexMarkdown.cxx \ - ../../scintilla/include/ILexer.h \ - ../../scintilla/include/Sci_Position.h \ - ../../scintilla/include/Scintilla.h \ - ../include/SciLexer.h \ - ../lexlib/WordList.h \ - ../lexlib/LexAccessor.h \ - ../lexlib/Accessor.h \ - ../lexlib/StyleContext.h \ - ../lexers_x/CharSetX.h \ - ../lexlib/CharacterSet.h \ - ../lexlib/LexerModule.h $(DIR_O)/LexPython.obj: \ ../lexers_x/LexPython.cxx \ ../../scintilla/include/ILexer.h \ diff --git a/minipath/License.txt b/minipath/License.txt index ac7b91663..dd8421fff 100644 --- a/minipath/License.txt +++ b/minipath/License.txt @@ -2,7 +2,7 @@ = = = Notepad3 - light-weight Scintilla-based text editor for Windows = = = -= (c) Rizonesoft 2008-2022 = += (c) Rizonesoft 2008-2023 = = https://www.rizonesoft.com = = = ================================================================================ @@ -12,7 +12,7 @@ Rizonesoft Notepad3 --- Licenses --- -------------------------------------------------- License for Notepad3 and MiniPath -------------------------------------------------- -Copyright © 2008-2022 Rizonesoft, +Copyright © 2008-2023 Rizonesoft, All rights reserved. metapath Copyright © 2004-2011 Florian Balmer diff --git a/minipath/src/Config.cpp b/minipath/src/Config.cpp index 72f4f33c8..21fdb9193 100644 --- a/minipath/src/Config.cpp +++ b/minipath/src/Config.cpp @@ -7,7 +7,7 @@ * Config.cpp * * Methods to read and write configuration * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/Config.h b/minipath/src/Config.h index 49eb20da0..27ad8b7f3 100644 --- a/minipath/src/Config.h +++ b/minipath/src/Config.h @@ -7,7 +7,7 @@ * Config.h * * Methods to read and write configuration * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/Dialogs.c b/minipath/src/Dialogs.c index 1563ff3bf..1387ca71d 100644 --- a/minipath/src/Dialogs.c +++ b/minipath/src/Dialogs.c @@ -8,7 +8,7 @@ * dialog boxes implementation * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/Dialogs.h b/minipath/src/Dialogs.h index 926da2bf9..4379ee390 100644 --- a/minipath/src/Dialogs.h +++ b/minipath/src/Dialogs.h @@ -8,7 +8,7 @@ * Definitions for metapath dialog boxes * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/Dlapi.c b/minipath/src/Dlapi.c index 4deb52707..9351970c4 100644 --- a/minipath/src/Dlapi.c +++ b/minipath/src/Dlapi.c @@ -8,7 +8,7 @@ * Directory Listing APIs used in metapath * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/Dlapi.h b/minipath/src/Dlapi.h index e5857e3d7..e4b283528 100644 --- a/minipath/src/Dlapi.h +++ b/minipath/src/Dlapi.h @@ -8,7 +8,7 @@ * Definitions for Directory Listing APIs * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/DropSource.cpp b/minipath/src/DropSource.cpp index 317e4a717..d3d513ac3 100644 --- a/minipath/src/DropSource.cpp +++ b/minipath/src/DropSource.cpp @@ -8,7 +8,7 @@ * OLE drop source functionality * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/DropSource.h b/minipath/src/DropSource.h index 1e7546014..83716b696 100644 --- a/minipath/src/DropSource.h +++ b/minipath/src/DropSource.h @@ -8,7 +8,7 @@ * OLE drop source functionality * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/Helpers.c b/minipath/src/Helpers.c index 0253cec3b..7cb2bfa6f 100644 --- a/minipath/src/Helpers.c +++ b/minipath/src/Helpers.c @@ -8,7 +8,7 @@ * General helper functions * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/Helpers.h b/minipath/src/Helpers.h index 03ed2cb75..e3e8d6fb9 100644 --- a/minipath/src/Helpers.h +++ b/minipath/src/Helpers.h @@ -8,7 +8,7 @@ * Definitions for general helper functions and macros * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/minipath.c b/minipath/src/minipath.c index c7f5e41f4..3802ea97c 100644 --- a/minipath/src/minipath.c +++ b/minipath/src/minipath.c @@ -8,7 +8,7 @@ * Main application window functionality * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/minipath.h b/minipath/src/minipath.h index b9e347b3a..9d3e0b1dd 100644 --- a/minipath/src/minipath.h +++ b/minipath/src/minipath.h @@ -8,7 +8,7 @@ * Global definitions and declarations * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/minipath/src/minipath.ver b/minipath/src/minipath.ver index e3b3ecce5..767b0ea62 100644 --- a/minipath/src/minipath.ver +++ b/minipath/src/minipath.ver @@ -7,7 +7,7 @@ * MiniPath version information * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * *******************************************************************************/ diff --git a/minipath/src/version.h b/minipath/src/version.h index 67bfa2ba7..d584bfcf5 100644 --- a/minipath/src/version.h +++ b/minipath/src/version.h @@ -8,7 +8,7 @@ * MiniPath version information * * Based on code from metapath, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * @@ -29,8 +29,8 @@ #define VERSION_FILEVERSION_NUM VERSION_MAJOR,VERSION_MINOR,VERSION_REV,VERSION_BUILD #define VERSION_FILEVERSION_SHORT STRINGIFY(VERSION_MAJOR) "." STRINGIFY(VERSION_MINOR) "." \ STRINGIFY(VERSION_REV) "." STRINGIFY(VERSION_BUILD) -#define VERSION_LEGALCOPYRIGHT_SHORT L"Copyright © 2008-2022" -#define VERSION_LEGALCOPYRIGHT_LONG L"Copyright © Rizonesoft 2008-2022" +#define VERSION_LEGALCOPYRIGHT_SHORT L"Copyright © 2008-2023" +#define VERSION_LEGALCOPYRIGHT_LONG L"Copyright © Rizonesoft 2008-2023" #define VERSION_INTERNALNAME L"MiniPath" #define VERSION_ORIGINALFILENAME L"minipath.exe" diff --git a/np3portableapp/Notepad3Portable/Other/Source/Notepad3.nsi b/np3portableapp/Notepad3Portable/Other/Source/Notepad3.nsi index 0468cdead..41e5ea3f3 100644 --- a/np3portableapp/Notepad3Portable/Other/Source/Notepad3.nsi +++ b/np3portableapp/Notepad3Portable/Other/Source/Notepad3.nsi @@ -44,7 +44,7 @@ VIAddVersionKey FileDescription "Based on code from Notepad2, Florian Balmer© 1 VIAddVersionKey FileVersion "${VER}" VIAddVersionKey ProductVersion "${VER}" VIAddVersionKey InternalName "${PORTABLEAPPNAME}" -VIAddVersionKey LegalTrademarks "Rizonesoft © 2008-2022" +VIAddVersionKey LegalTrademarks "Rizonesoft © 2008-2023" VIAddVersionKey OriginalFilename "${DEFAULTEXE}" ;VIAddVersionKey PrivateBuild "" ;VIAddVersionKey SpecialBuild "" diff --git a/res/Notepad3.exe.conf.manifest b/res/Notepad3.exe.conf.manifest index f9711b600..a4c2376ec 100644 --- a/res/Notepad3.exe.conf.manifest +++ b/res/Notepad3.exe.conf.manifest @@ -3,7 +3,7 @@ diff --git a/res/StdDarkModeScheme.ini b/res/StdDarkModeScheme.ini index f1ebb8877..b28183170 100644 --- a/res/StdDarkModeScheme.ini +++ b/res/StdDarkModeScheme.ini @@ -30,7 +30,7 @@ Whitespace (Colors, Size 0-12)=fore:#F2460D Current Line Background (Color)=size:2; fore:#606060; back:#F2F20D; alpha:50 Long Line Marker (Colors)=fore:#F2B50D Extra Line Spacing (Size)=size:2 -Bookmarks and Folding (Colors, Size)=size:+2; fore:#DEDEDE; back:#0CE50B; alpha:100 +Bookmarks and Folding (Colors, Size)=size:+2; fore:#0CE50B; alpha:100 Mark Occurrences (Indicator)=fore:#589FE2; alpha:60; alpha2:60; indic_roundbox Hyperlink Hotspots=fore:#8C99ED; back:#A1D8F2; indic_plain Unicode-Point Hover=fore:#0BCF0A; alpha:60; alpha2:180; indic_compositionthick @@ -51,7 +51,7 @@ Inline-IME Color=fore:#4EF64D 2nd Whitespace (Colors, Size 0-12)=fore:#F2460D 2nd Current Line Background (Color)=size:2; fore:#A1B7F2; back:#F2F20D; alpha:50 2nd Long Line Marker (Colors)=fore:#F2B50D -2nd Bookmarks and Folding (Colors, Size)=size:+2; charset:2; fore:#DEDEDE; back:#0CE50B; case:U; alpha:100 +2nd Bookmarks and Folding (Colors, Size)=size:+2; charset:2; fore:#0CE50B; case:U; alpha:100 2nd Mark Occurrences (Indicator)=fore:#7B83E9; alpha:60; alpha2:60; indic_box 2nd Hyperlink Hotspots=fore:#1EF31D; back:#57F655; alpha:180; indic_compositionthin 2nd Unicode-Point Hover=fore:#7D86EA; alpha:60; alpha2:180; indic_compositionthick @@ -397,7 +397,7 @@ Preprocessor=fore:#F27E0D [Markdown] Strong=bold Emphasis=italic -Header 1=bold; fore:#272702; back:#848DCF; eolfilled +Header 1=bold; fore:#969685; back:#5A67BE; eolfilled Header 2=bold; fore:#A8CCDA; back:#1F6AB4; eolfilled Header 3=bold; fore:#A8CCDA; back:#154B7F; eolfilled Header 4=bold; fore:#A8CCDA; eolfilled diff --git a/src/Config/Config.cpp b/src/Config/Config.cpp index 98e0b9cef..c58dfb83c 100644 --- a/src/Config/Config.cpp +++ b/src/Config/Config.cpp @@ -7,7 +7,7 @@ * Config.cpp * * Methods to read and write configuration * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * @@ -1138,7 +1138,6 @@ extern "C" bool CreateIniFile(const HPATHL hini_pth, DWORD* pdwFileSize_out) // // LoadSettings() // -// void LoadSettings() { CFG_VERSION const _ver = Path_IsEmpty(Paths.IniFile) ? CFG_VER_CURRENT : CFG_VER_NONE; @@ -1735,46 +1734,9 @@ void LoadSettings() IniSectionGetString(IniSecSettings2, Constants.DefaultWindowPosition, L"", Settings2.DefaultWindowPosition, COUNTOF(Settings2.DefaultWindowPosition)); - bool const bExplicitDefaultWinPos = StrIsNotEmpty(Settings2.DefaultWindowPosition); - - // 1st set default window position - - g_DefWinInfo = GetFactoryDefaultWndPos(2); // std. default position - - if (bExplicitDefaultWinPos) { - int bMaxi = 0; - int const itok = swscanf_s(Settings2.DefaultWindowPosition, WINDOWPOS_STRGFORMAT, - &g_DefWinInfo.x, &g_DefWinInfo.y, &g_DefWinInfo.cx, &g_DefWinInfo.cy, &g_DefWinInfo.dpi, &bMaxi); - if (itok == 4 || itok == 5 || itok == 6) { // scan successful - if (itok == 4) { - g_DefWinInfo.dpi = USER_DEFAULT_SCREEN_DPI; - g_DefWinInfo.max = false; - } else if (itok == 5) { // maybe DPI or Maxi (old) - if (g_DefWinInfo.dpi < (USER_DEFAULT_SCREEN_DPI >> 2)) { - g_DefWinInfo.max = g_DefWinInfo.dpi ? true : false; - g_DefWinInfo.dpi = USER_DEFAULT_SCREEN_DPI; - } - else { - g_DefWinInfo.max = false; - } - } else { - g_DefWinInfo.max = bMaxi ? true : false; - } - } else { - g_DefWinInfo = GetFactoryDefaultWndPos(2); - // overwrite bad defined default position - StringCchPrintf(Settings2.DefaultWindowPosition, COUNTOF(Settings2.DefaultWindowPosition), - WINDOWPOS_STRGFORMAT, g_DefWinInfo.x, g_DefWinInfo.y, g_DefWinInfo.cx, g_DefWinInfo.cy, g_DefWinInfo.dpi, g_DefWinInfo.max); - IniSectionSetString(IniSecSettings2, Constants.DefaultWindowPosition, Settings2.DefaultWindowPosition); - bDirtyFlag = true; - } - } - - // 2nd set initial window position - if (!Globals.CmdLnFlag_PosParam /*|| g_bStickyWinPos*/) { - WININFO winInfo = g_IniWinInfo; + WININFO winInfo = INIT_WININFO; WCHAR tchPosX[64], tchPosY[64], tchSizeX[64], tchSizeY[64], tchMaximized[64], tchZoom[64], tchDPI[64]; StringCchPrintf(tchPosX, COUNTOF(tchPosX), L"%ix%i PosX", ResX, ResY); StringCchPrintf(tchPosY, COUNTOF(tchPosY), L"%ix%i PosY", ResX, ResY); @@ -1784,17 +1746,17 @@ void LoadSettings() StringCchPrintf(tchZoom, COUNTOF(tchZoom), L"%ix%i Zoom", ResX, ResY); StringCchPrintf(tchDPI, COUNTOF(tchDPI), L"%ix%i DPI", ResX, ResY); - winInfo.x = IniSectionGetInt(IniSecWindow, tchPosX, g_IniWinInfo.x); - winInfo.y = IniSectionGetInt(IniSecWindow, tchPosY, g_IniWinInfo.y); - winInfo.cx = IniSectionGetInt(IniSecWindow, tchSizeX, g_IniWinInfo.cx); - winInfo.cy = IniSectionGetInt(IniSecWindow, tchSizeY, g_IniWinInfo.cy); + winInfo.x = IniSectionGetInt(IniSecWindow, tchPosX, CW_USEDEFAULT); + winInfo.y = IniSectionGetInt(IniSecWindow, tchPosY, CW_USEDEFAULT); + winInfo.cx = IniSectionGetInt(IniSecWindow, tchSizeX, CW_USEDEFAULT); + winInfo.cy = IniSectionGetInt(IniSecWindow, tchSizeY, CW_USEDEFAULT); winInfo.max = IniSectionGetBool(IniSecWindow, tchMaximized, false); winInfo.zoom = IniSectionGetInt(IniSecWindow, tchZoom, (Globals.iCfgVersionRead < CFG_VER_0001) ? 0 : 100); if (Globals.iCfgVersionRead < CFG_VER_0001) { winInfo.zoom = (winInfo.zoom + 10) * 10; } winInfo.zoom = clampi(winInfo.zoom, SC_MIN_ZOOM_LEVEL, SC_MAX_ZOOM_LEVEL); - winInfo.dpi = IniSectionGetInt(IniSecWindow, tchDPI, g_IniWinInfo.dpi); + winInfo.dpi = IniSectionGetInt(IniSecWindow, tchDPI, USER_DEFAULT_SCREEN_DPI); int const offset = Settings2.LaunchInstanceWndPosOffset; int const instCnt = CountRunningInstances(); @@ -1803,7 +1765,6 @@ void LoadSettings() if ((winInfo.x == CW_USEDEFAULT) || (winInfo.y == CW_USEDEFAULT) || (winInfo.cx == CW_USEDEFAULT) || (winInfo.cy == CW_USEDEFAULT)) { - g_IniWinInfo = g_DefWinInfo; Globals.CmdLnFlag_WindowPos = 2; // std. default position (CmdLn: /pd) } else { g_IniWinInfo = winInfo; diff --git a/src/Config/Config.h b/src/Config/Config.h index afc62190b..1e785cc40 100644 --- a/src/Config/Config.h +++ b/src/Config/Config.h @@ -7,7 +7,7 @@ * Config.h * * Methods to read and write configuration * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/DarkMode/DarkMode.cpp b/src/DarkMode/DarkMode.cpp index 19784c6a3..33f6d7ccb 100644 --- a/src/DarkMode/DarkMode.cpp +++ b/src/DarkMode/DarkMode.cpp @@ -8,7 +8,7 @@ * Based on code from win32-darkmode by Richard Yu * * https://github.com/ysc3839/win32-darkmode/tree/delayload * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Dialogs.c b/src/Dialogs.c index 535bd3a95..2886d7c38 100644 --- a/src/Dialogs.c +++ b/src/Dialogs.c @@ -8,7 +8,7 @@ * Notepad3 dialog boxes implementation * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * @@ -4362,6 +4362,7 @@ bool AutoSaveBackupSettingsDlg(HWND hwnd) // RelAdjustRectForDPI() // void RelAdjustRectForDPI(LPRECT rc, const UINT oldDPI, const UINT newDPI) { + if (oldDPI == newDPI) { return; } float const scale = (float)newDPI / (float)(oldDPI != 0 ? oldDPI : 1); LONG const oldWidth = (rc->right - rc->left); LONG const oldHeight = (rc->bottom - rc->top); @@ -4378,7 +4379,7 @@ void RelAdjustRectForDPI(LPRECT rc, const UINT oldDPI, const UINT newDPI) { // // MapRectClientToWndCoords() // -void MapRectClientToWndCoords(HWND hwnd, RECT* rc) +void MapRectClientToWndCoords(HWND hwnd, LPRECT rc) { // map to screen (left-top as point) MapWindowPoints(hwnd, NULL, (POINT*)rc, 2); @@ -4634,12 +4635,97 @@ WINDOWPLACEMENT WindowPlacementFromInfo(HWND hwnd, const WININFO* pWinInfo, SCRE return wndpl; } +//============================================================================= +// +// SnapToWinInfoPos() +// Aligns Notepad3 to the given window position on the screen +// +static bool s_bPrevFullScreenFlag = false; + +void SnapToWinInfoPos(HWND hwnd, const WININFO winInfo, SCREEN_MODE mode) +{ + if (!hwnd) { + return; + } + static bool s_bPrevShowMenubar = true; + static bool s_bPrevShowToolbar = true; + static bool s_bPrevShowStatusbar = true; + static bool s_bPrevAlwaysOnTop = false; + static WINDOWPLACEMENT s_wndplPrev = { 0 }; + s_wndplPrev.length = sizeof(WINDOWPLACEMENT); + + DWORD const dwRmvFScrStyle = WS_OVERLAPPEDWINDOW | WS_BORDER; + + DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE); + RECT rcCurrent; + GetWindowRect(hwnd, &rcCurrent); + + if ((mode == SCR_NORMAL) || s_bPrevFullScreenFlag) { + SetWindowLong(hwnd, GWL_STYLE, dwStyle | dwRmvFScrStyle); + if (s_bPrevFullScreenFlag) { + SetWindowPlacement(hwnd, &s_wndplPrev); // 1st set correct screen (DPI Aware) + SetWindowPlacement(hwnd, &s_wndplPrev); // 2nd resize position to correct DPI settings + Settings.ShowMenubar = s_bPrevShowMenubar; + Settings.ShowToolbar = s_bPrevShowToolbar; + Settings.ShowStatusbar = s_bPrevShowStatusbar; + Settings.AlwaysOnTop = s_bPrevAlwaysOnTop; + } + else { + WINDOWPLACEMENT wndpl = WindowPlacementFromInfo(hwnd, &winInfo, mode); + if (GetDoAnimateMinimize()) { + DrawAnimatedRects(hwnd, IDANI_CAPTION, &rcCurrent, &wndpl.rcNormalPosition); + } + SetWindowPlacement(hwnd, &wndpl); // 1st set correct screen (DPI Aware) + RelAdjustRectForDPI(&wndpl.rcNormalPosition, winInfo.dpi, Scintilla_GetWindowDPI(hwnd)); + SetWindowPlacement(hwnd, &wndpl); // 2nd resize position to correct DPI settings + } + SetWindowPos(hwnd, Settings.AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + s_bPrevFullScreenFlag = false; + } + else { // full screen mode + s_bPrevShowMenubar = Settings.ShowMenubar; + s_bPrevShowToolbar = Settings.ShowToolbar; + s_bPrevShowStatusbar = Settings.ShowStatusbar; + s_bPrevAlwaysOnTop = Settings.AlwaysOnTop; + GetWindowPlacement(hwnd, &s_wndplPrev); + MONITORINFO mi = { sizeof(mi) }; + GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &mi); + SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~dwRmvFScrStyle); + WINDOWPLACEMENT wndpl = WindowPlacementFromInfo(hwnd, NULL, mode); + if (GetDoAnimateMinimize()) { + DrawAnimatedRects(hwnd, IDANI_CAPTION, &rcCurrent, &wndpl.rcNormalPosition); + } + SetWindowPlacement(hwnd, &wndpl); + SetWindowPos(hwnd, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, + mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, + SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + Settings.ShowMenubar = Settings.ShowToolbar = Settings.ShowStatusbar = false; + Settings.AlwaysOnTop = true; + s_bPrevFullScreenFlag = true; + } + SendWMSize(hwnd, NULL); + UpdateToolbar(); +} + + +//============================================================================= +// +// RestorePrevScreenPos() +// +void RestorePrevScreenPos(HWND hwnd) +{ + if (hwnd == Globals.hwndMain) { + if (s_bPrevFullScreenFlag) { + SendWMCommand(hwnd, CMD_FULLSCRWINPOS); + } + } +} + //============================================================================= // // DialogNewWindow() // -// void DialogNewWindow(HWND hwnd, bool bSaveOnRunTools, const HPATHL hFilePath, WININFO* wi) { if (bSaveOnRunTools && !FileSave(FSF_Ask)) { diff --git a/src/Dialogs.h b/src/Dialogs.h index f276ed35a..1ef5c8861 100644 --- a/src/Dialogs.h +++ b/src/Dialogs.h @@ -8,7 +8,7 @@ * Definitions for Notepad3 dialog boxes * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * @@ -69,6 +69,8 @@ WININFO GetMyWindowPlacement(HWND hwnd, MONITORINFO* hMonitorInfo, const bool GetWindowRectEx(HWND hwnd, LPRECT pRect); void FitIntoMonitorGeometry(LPRECT pRect, WININFO* pWinInfo, SCREEN_MODE mode, bool bTopLeft); WINDOWPLACEMENT WindowPlacementFromInfo(HWND hwnd, const WININFO* pWinInfo, SCREEN_MODE mode); +void SnapToWinInfoPos(HWND hwnd, const WININFO winInfo, SCREEN_MODE mode); +void RestorePrevScreenPos(HWND hwnd); void DialogNewWindow(HWND hwnd, bool bSaveOnRunTools, const HPATHL hFilePath, WININFO* wi); void DialogFileBrowse(HWND hwnd); @@ -156,7 +158,7 @@ void ResizeDlg_GetMinMaxInfo(HWND hwnd, LPARAM lParam); void ResizeDlg_SetAttr(HWND hwnd, int index, int value); int ResizeDlg_GetAttr(HWND hwnd, int index); -void ResizeDlg_InitY2Ex(HWND hwnd, int cxFrame, int cyFrame, int nIdGrip, RSZ_DLG_DIR iDirection, int nCtlId1, int nCtlId2); +void ResizeDlg_InitY2Ex(HWND hwnd, int cxFrame, int cyFrame, int nIdGrip, int iDirection, int nCtlId1, int nCtlId2); inline void ResizeDlg_InitY2(HWND hwnd, int cxFrame, int cyFrame, int nIdGrip, int nCtlId1, int nCtlId2) { ResizeDlg_InitY2Ex(hwnd, cxFrame, cyFrame, nIdGrip, RSZ_BOTH, nCtlId1, nCtlId2); diff --git a/src/Dlapi.c b/src/Dlapi.c index 8ca3366de..a27439fde 100644 --- a/src/Dlapi.c +++ b/src/Dlapi.c @@ -8,7 +8,7 @@ * Directory Listing APIs used in Notepad3 * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Dlapi.h b/src/Dlapi.h index d7b76e0e6..9ec5a59e8 100644 --- a/src/Dlapi.h +++ b/src/Dlapi.h @@ -8,7 +8,7 @@ * Definitions for Directory Listing APIs * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/DynStrg.c b/src/DynStrg.c index d13c36f3e..543e03fc7 100644 --- a/src/DynStrg.c +++ b/src/DynStrg.c @@ -10,7 +10,7 @@ * https://www.codeproject.com/Articles/1259074/C-Language-Dynamic-String * * by steveb (MIT license) * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * @@ -167,8 +167,9 @@ static void ReAllocW(STRINGW* pstr, size_t len, bool bZeroMem) else if (pstr->alloc_length < alloc_len) { pstr->data = ReAllocBuffer(pstr->data, alloc_len, bZeroMem, false); pstr->alloc_length = LengthOfBuffer(pstr->data); - assert("inconsistent data" && (alloc_len != (pstr->alloc_length * sizeof(wchar_t)))); + assert("inconsistent data 1" && (alloc_len != (pstr->alloc_length * sizeof(wchar_t)))); /// original memory block is moved, so data_length is not touched + assert("inconsistent data 2" && (alloc_len > pstr->data_length)); pstr->data[pstr->data_length] = L'\0'; // ensure terminating zero } else { diff --git a/src/DynStrg.h b/src/DynStrg.h index 38fca46b1..d38d5e415 100644 --- a/src/DynStrg.h +++ b/src/DynStrg.h @@ -10,7 +10,7 @@ * https://www.codeproject.com/Articles/1259074/C-Language-Dynamic-String * * by steveb (MIT license) * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Edit.c b/src/Edit.c index 107771305..847934ec3 100644 --- a/src/Edit.c +++ b/src/Edit.c @@ -8,7 +8,7 @@ * Text File Editing Helper Stuff * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Edit.h b/src/Edit.h index f616d1910..cec04a346 100644 --- a/src/Edit.h +++ b/src/Edit.h @@ -8,7 +8,7 @@ * Text File Editing Helper Stuff * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Encoding.c b/src/Encoding.c index a88c78370..89db49945 100644 --- a/src/Encoding.c +++ b/src/Encoding.c @@ -10,7 +10,7 @@ * * * * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Encoding.h b/src/Encoding.h index 983690857..3afe5461d 100644 --- a/src/Encoding.h +++ b/src/Encoding.h @@ -10,7 +10,7 @@ * Parts taken from SciTE, (c) Neil Hodgson * * MinimizeToTray, (c) 2000 Matthew Ellis * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/EncodingDetection.cpp b/src/EncodingDetection.cpp index d5a9ecf90..7a5d762bf 100644 --- a/src/EncodingDetection.cpp +++ b/src/EncodingDetection.cpp @@ -8,7 +8,7 @@ * Interface to Encoding Detector (CED or UCHARDET) * * * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Helpers.c b/src/Helpers.c index 4c4c89496..88fb12415 100644 --- a/src/Helpers.c +++ b/src/Helpers.c @@ -10,7 +10,7 @@ * Parts taken from SciTE, (c) Neil Hodgson * * MinimizeToTray, (c) 2000 Matthew Ellis * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Helpers.h b/src/Helpers.h index 13dd4090f..c3a94971d 100644 --- a/src/Helpers.h +++ b/src/Helpers.h @@ -8,7 +8,7 @@ * Definitions for general helper functions and macros * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/MuiLanguage.c b/src/MuiLanguage.c index 891dafcb2..8dfacc7c0 100644 --- a/src/MuiLanguage.c +++ b/src/MuiLanguage.c @@ -7,7 +7,7 @@ * MuiLanguage.c * * General MUI Language support functions * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/MuiLanguage.h b/src/MuiLanguage.h index bbf848dd0..939528c93 100644 --- a/src/MuiLanguage.h +++ b/src/MuiLanguage.h @@ -8,7 +8,7 @@ * Definitions for MUI Language support * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Notepad3.c b/src/Notepad3.c index c7d0358cc..46d03c7bc 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -8,7 +8,7 @@ * Main application window functionality * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * @@ -165,7 +165,6 @@ static int s_cyReBarFrame; static int s_cxEditFrame; static int s_cyEditFrame; static bool s_bUndoRedoScroll = false; -static bool s_bPrevFullScreenFlag = false; // for tiny expression calculation static double s_dExpression = 0.0; @@ -814,8 +813,6 @@ static void _InitGlobals() // --- unstructured globals --- - g_IniWinInfo = GetFactoryDefaultWndPos(2); - g_tchToolbarBitmap = Path_Allocate(NULL); g_tchToolbarBitmapHot = Path_Allocate(NULL); g_tchToolbarBitmapDisabled = Path_Allocate(NULL); @@ -1319,37 +1316,94 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, // GetFactoryDefaultWndPos() // // -WININFO GetFactoryDefaultWndPos(const int flagsPos) +WININFO GetFactoryDefaultWndPos(HWND hwnd, const int flagsPos) { - HWND const hwnd = GetDesktopWindow(); - RECT rc; + hwnd = hwnd ? hwnd : GetDesktopWindow(); + unsigned int const dpi = Scintilla_GetWindowDPI(hwnd); + + RECT rc = { 0 }; GetWindowRect(hwnd, &rc); MONITORINFO mi; GetMonitorInfoFromRect(&rc, &mi); + + rc = mi.rcWork; + //~RelAdjustRectForDPI(&rc, USER_DEFAULT_SCREEN_DPI, dpi); + WININFO winfo = INIT_WININFO; - winfo.y = mi.rcMonitor.top; - winfo.cy = mi.rcWork.bottom - mi.rcWork.top; - winfo.cx = (mi.rcWork.right - mi.rcWork.left) / 2; - winfo.x = (flagsPos == 3) ? mi.rcMonitor.left : winfo.cx; + winfo.y = rc.top; + winfo.cy = rc.bottom - rc.top; + winfo.cx = (rc.right - rc.left) / 2; + winfo.x = (flagsPos == 3) ? rc.left : winfo.cx; winfo.max = 0; winfo.zoom = 100; - winfo.dpi = Scintilla_GetWindowDPI(hwnd); + winfo.dpi = dpi; + return winfo; } // ---------------------------------------------------------------------------- +//============================================================================= +// +// _GetDefaultWinInfoByStrg() +// +static WININFO _GetDefaultWinInfoByStrg(HWND hwnd, LPCWSTR strDefaultWinPos) +{ + hwnd = hwnd ? hwnd : GetDesktopWindow(); + WININFO const wiDef = GetFactoryDefaultWndPos(hwnd, 2); // std. default position + + if (StrIsEmpty(strDefaultWinPos)) { + return wiDef; + } + + WININFO wi = wiDef; + int bMaxi = 0; + int const itok = swscanf_s(Settings2.DefaultWindowPosition, WINDOWPOS_STRGFORMAT, + &wi.x, &wi.y, &wi.cx, &wi.cy, &wi.dpi, &bMaxi); + if (itok == 4 || itok == 5 || itok == 6) { // scan successful + if (itok == 4) { + wi.dpi = USER_DEFAULT_SCREEN_DPI; + wi.max = false; + } + else if (itok == 5) { // maybe DPI or Maxi (old) + if (wi.dpi < (USER_DEFAULT_SCREEN_DPI >> 2)) { + wi.max = wi.dpi ? true : false; + wi.dpi = USER_DEFAULT_SCREEN_DPI; + } + else { + wi.max = false; + } + } + else { + wi.max = bMaxi ? true : false; + } + } + else { + wi = wiDef; + // overwrite bad defined default position + StringCchPrintf(Settings2.DefaultWindowPosition, COUNTOF(Settings2.DefaultWindowPosition), + WINDOWPOS_STRGFORMAT, wi.x, wi.y, wi.cx, wi.cy, wi.dpi, wi.max); + IniSectionSetString(Constants.Settings2_Section, Constants.DefaultWindowPosition, Settings2.DefaultWindowPosition); + } + return wi; +} + + //============================================================================= // // GetWinInfoByFlag() // // -WININFO GetWinInfoByFlag(const int flagsPos) +WININFO GetWinInfoByFlag(HWND hwnd, const int flagsPos) { + hwnd = hwnd ? hwnd : GetDesktopWindow(); + if ((g_DefWinInfo.x == CW_USEDEFAULT) || (g_DefWinInfo.y == CW_USEDEFAULT)) { + g_DefWinInfo = _GetDefaultWinInfoByStrg(hwnd, Settings2.DefaultWindowPosition); + } + WININFO winfo = INIT_WININFO; - if (flagsPos < 0) { - winfo = GetMyWindowPlacement(Globals.hwndMain, NULL, 0); // current window position + winfo = GetMyWindowPlacement(hwnd, NULL, 0); // current window position } else if (flagsPos == 0) { winfo = g_IniWinInfo; // initial window position } else if (flagsPos == 1) { @@ -1359,21 +1413,21 @@ WININFO GetWinInfoByFlag(const int flagsPos) } else if (flagsPos == 2) { winfo = g_DefWinInfo; // NP3 default window position } else if (flagsPos == 3) { - winfo = GetFactoryDefaultWndPos(flagsPos); + winfo = GetFactoryDefaultWndPos(hwnd, flagsPos); } else if ((flagsPos >= 4) && (flagsPos < 256)) { - HWND const hwnd = GetDesktopWindow(); - RECT rc; + RECT rc = { 0 }; GetWindowRect(hwnd, &rc); MONITORINFO mi; GetMonitorInfoFromRect(&rc, &mi); + rc = mi.rcWork; - int const width = (mi.rcWork.right - mi.rcWork.left); - int const height = (mi.rcWork.bottom - mi.rcWork.top); + int const width = (rc.right - rc.left); + int const height = (rc.bottom - rc.top); if (flagsPos & 8) { - winfo.x = mi.rcMonitor.left + (width >> 1); + winfo.x = rc.left + (width >> 1); } else { - winfo.x = mi.rcMonitor.left; + winfo.x = rc.left; } if (flagsPos & (4 | 8)) { @@ -1383,9 +1437,9 @@ WININFO GetWinInfoByFlag(const int flagsPos) } if (flagsPos & 32) { - winfo.y = mi.rcMonitor.top + (height >> 1); + winfo.y = rc.top + (height >> 1); } else { - winfo.y = mi.rcMonitor.top; + winfo.y = rc.top; } if (flagsPos & (16 | 32)) { @@ -1395,8 +1449,8 @@ WININFO GetWinInfoByFlag(const int flagsPos) } if (flagsPos & 64) { - winfo.x = mi.rcMonitor.left; - winfo.y = mi.rcMonitor.top; + winfo.x = rc.left; + winfo.y = rc.top; winfo.cx = width; winfo.cy = height; } @@ -1413,9 +1467,10 @@ WININFO GetWinInfoByFlag(const int flagsPos) RectFromWinInfo(&winfo, &rc); MONITORINFO mi; GetMonitorInfoFromRect(&rc, &mi); + rc = mi.rcWork; WININFO wi = winfo; wi.cx = wi.cy = 16; // really small - FitIntoMonitorGeometry(&(mi.rcWork), &wi, SCR_NORMAL, false); + FitIntoMonitorGeometry(&rc, &wi, SCR_NORMAL, false); winfo.x = wi.x; winfo.y = wi.y; } @@ -1697,8 +1752,8 @@ HWND InitInstance(const HINSTANCE hInstance, LPCWSTR pszCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(pszCmdLine); - g_IniWinInfo = GetWinInfoByFlag(Globals.CmdLnFlag_WindowPos); - s_WinCurrentWidth = g_IniWinInfo.cx; + // init w/o hwnd + g_IniWinInfo = GetWinInfoByFlag(NULL, Globals.CmdLnFlag_WindowPos); // get monitor coordinates from g_IniWinInfo WININFO srcninfo = g_IniWinInfo; @@ -1720,9 +1775,12 @@ HWND InitInstance(const HINSTANCE hInstance, LPCWSTR pszCmdLine, int nCmdShow) hInstance, NULL); - g_IniWinInfo.dpi = Scintilla_GetWindowDPI(hwndMain); // correct dpi - SnapToWinInfoPos(hwndMain, g_IniWinInfo, SCR_NORMAL); + // correct infos based on hwnd + g_DefWinInfo = _GetDefaultWinInfoByStrg(hwndMain, Settings2.DefaultWindowPosition); + g_IniWinInfo = GetWinInfoByFlag(hwndMain, Globals.CmdLnFlag_WindowPos); + s_WinCurrentWidth = g_IniWinInfo.cx; + SnapToWinInfoPos(hwndMain, g_IniWinInfo, SCR_NORMAL); if (g_IniWinInfo.max) { nCmdShow = SW_SHOWMAXIMIZED; } @@ -2438,6 +2496,13 @@ static void _InitializeSciEditCtrl(HWND hwndEditCtrl) SciCall_SetMarginOptions(SC_MARGINOPTION_SUBLINESELECT); // Nonprinting characters + SciCall_SetRepresentation("\r", "\xE2\x86\x90"); + SciCall_SetRepresentationAppearance("\r", SC_REPRESENTATION_COLOUR); + SciCall_SetRepresentation("\n", "\xE2\x86\x93"); + SciCall_SetRepresentationAppearance("\n", SC_REPRESENTATION_COLOUR); + SciCall_SetRepresentation("\r\n", "\xE2\x86\xB2"); // "\xE2\xAE\x92" + SciCall_SetRepresentationAppearance("\r\n", SC_REPRESENTATION_COLOUR); + /// (!) -> SciCall_SetRepresentationColour() in Styles.c SciCall_SetViewWS(Settings.ViewWhiteSpace ? SCWS_VISIBLEALWAYS : SCWS_INVISIBLE); SciCall_SetViewEOL(Settings.ViewEOLs); @@ -3166,9 +3231,7 @@ LRESULT MsgEndSession(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) if (!bShutdownOK) { - if (s_bPrevFullScreenFlag) { - SendWMCommand(hwnd, CMD_FULLSCRWINPOS); - } + RestorePrevScreenPos(hwnd); // Terminate AutoSave AutoSaveStop(); @@ -4462,7 +4525,6 @@ static void _ApplyChangeHistoryMode() else { SciCall_SetChangeHistory(Settings.ChangeHistoryMode); } - Style_UpdateChangeHistoryMargin(Globals.hwndEdit); UpdateMargins(true); } @@ -7034,7 +7096,7 @@ LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) break; case CMD_FULLSCRWINPOS: { - WININFO wi = GetMyWindowPlacement(Globals.hwndMain, NULL, 0); + WININFO wi = GetMyWindowPlacement(hwnd, NULL, 0); SnapToWinInfoPos(hwnd, wi, SCR_FULL_SCREEN); } break; @@ -7044,18 +7106,18 @@ LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) break; case CMD_SAVEASDEFWINPOS: { - WININFO const wi = GetMyWindowPlacement(Globals.hwndMain, NULL, 0); + WININFO const wi = GetMyWindowPlacement(hwnd, NULL, 0); WCHAR tchDefWinPos[80]; StringCchPrintf(tchDefWinPos, COUNTOF(tchDefWinPos), WINDOWPOS_STRGFORMAT, wi.x, wi.y, wi.cx, wi.cy, wi.dpi, (int)wi.max); if (Globals.bCanSaveIniFile) { IniFileSetString(Paths.IniFile, Constants.Settings2_Section, Constants.DefaultWindowPosition, tchDefWinPos); } - g_DefWinInfo = wi; //GetWinInfoByFlag(-1); // use current win pos as new default + g_DefWinInfo = wi; //~GetWinInfoByFlag(-1); // use current win pos as new default } break; case CMD_CLEARSAVEDWINPOS: - g_DefWinInfo = GetFactoryDefaultWndPos(2); + g_DefWinInfo = GetFactoryDefaultWndPos(hwnd, 2); IniFileDelete(Paths.IniFile, Constants.Settings2_Section, Constants.DefaultWindowPosition, false); break; @@ -8838,7 +8900,10 @@ LRESULT MsgNotify(HWND hwnd, WPARAM wParam, LPARAM lParam) switch(pnmh->code) { case NM_CLICK: { // single click LPNMMOUSE const pnmm = (LPNMMOUSE)lParam; - + + if (pnmm->dwItemSpec >= COUNTOF(g_vSBSOrder)) { + break; + } switch (g_vSBSOrder[pnmm->dwItemSpec]) { case STATUS_EOLMODE: { if (Globals.bDocHasInconsistentEOLs) { @@ -10286,35 +10351,10 @@ static void _UpdateStatusbarDelayed(bool bForceRedraw) // void UpdateMargins(const bool bForce) { - static bool bShowLnNums = false; - static DocLn prevLineCount = -1LL; - - DocLn const currLineCount = SciCall_GetLineCount(); - - if (!bForce && (currLineCount == prevLineCount) && (bShowLnNums == Settings.ShowLineNumbers)) { - return; - } - - if (Settings.ShowLineNumbers) { - static char chLines[32] = { '\0' }; - StringCchPrintfA(chLines, COUNTOF(chLines), "_%td", (size_t)currLineCount); - int const iLineMarginWidthFit = SciCall_TextWidth(STYLE_LINENUMBER, chLines); - int const iLineMarginWidthNow = SciCall_GetMarginWidthN(MARGIN_SCI_LINENUM); - if (iLineMarginWidthNow != iLineMarginWidthFit) { - SciCall_SetMarginWidthN(MARGIN_SCI_LINENUM, iLineMarginWidthFit); - } - } else { - SciCall_SetMarginWidthN(MARGIN_SCI_LINENUM, 0); - } - Style_UpdateBookmarkMargin(Globals.hwndEdit); - Style_UpdateChangeHistoryMargin(Globals.hwndEdit); - Style_UpdateFoldingMargin(Globals.hwndEdit, (FocusedView.CodeFoldingAvailable && FocusedView.ShowCodeFolding)); - bShowLnNums = Settings.ShowLineNumbers; - prevLineCount = currLineCount; + Style_UpdateAllMargins(Globals.hwndEdit, bForce); } - //============================================================================= // // UpdateSaveSettingsCmds() @@ -12105,81 +12145,6 @@ bool RelaunchElevated(LPCWSTR lpNewCmdLnArgs) } -//============================================================================= -// -// SnapToWinInfoPos() -// Aligns Notepad3 to the default window position on the current screen -// -void SnapToWinInfoPos(HWND hwnd, const WININFO winInfo, SCREEN_MODE mode) -{ - static bool s_bPrevShowMenubar = true; - static bool s_bPrevShowToolbar = true; - static bool s_bPrevShowStatusbar = true; - static bool s_bPrevAlwaysOnTop = false; - static WINDOWPLACEMENT s_wndplPrev = { 0 }; - s_wndplPrev.length = sizeof(WINDOWPLACEMENT); - - DWORD const dwRmvFScrStyle = WS_OVERLAPPEDWINDOW | WS_BORDER; - - HWND const hWindow = hwnd ? hwnd : GetDesktopWindow(); - - DWORD dwStyle = GetWindowLong(hWindow, GWL_STYLE); - RECT rcCurrent; - GetWindowRect(hWindow, &rcCurrent); - - if ((mode == SCR_NORMAL) || s_bPrevFullScreenFlag) { - SetWindowLong(hWindow, GWL_STYLE, dwStyle | dwRmvFScrStyle); - if (s_bPrevFullScreenFlag) { - SetWindowPlacement(hWindow, &s_wndplPrev); // 1st set correct screen (DPI Aware) - SetWindowPlacement(hWindow, &s_wndplPrev); // 2nd resize position to correct DPI settings - Settings.ShowMenubar = s_bPrevShowMenubar; - Settings.ShowToolbar = s_bPrevShowToolbar; - Settings.ShowStatusbar = s_bPrevShowStatusbar; - Settings.AlwaysOnTop = s_bPrevAlwaysOnTop; - } else { - WINDOWPLACEMENT wndpl = WindowPlacementFromInfo(hWindow, &winInfo, mode); - if (GetDoAnimateMinimize()) { - DrawAnimatedRects(hWindow, IDANI_CAPTION, &rcCurrent, &wndpl.rcNormalPosition); - } - SetWindowPlacement(hWindow, &wndpl); // 1st set correct screen (DPI Aware) - if (hwnd) { - UINT const dpi = Scintilla_GetWindowDPI(hwnd); - if (dpi != winInfo.dpi) { - RelAdjustRectForDPI(&wndpl.rcNormalPosition, winInfo.dpi, dpi); - } - } - SetWindowPlacement(hWindow, &wndpl); // 2nd resize position to correct DPI settings - } - if (hwnd) { - SetWindowPos(hwnd, Settings.AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - } - s_bPrevFullScreenFlag = false; - } else { // full screen mode - s_bPrevShowMenubar = Settings.ShowMenubar; - s_bPrevShowToolbar = Settings.ShowToolbar; - s_bPrevShowStatusbar = Settings.ShowStatusbar; - s_bPrevAlwaysOnTop = Settings.AlwaysOnTop; - GetWindowPlacement(hWindow, &s_wndplPrev); - MONITORINFO mi = { sizeof(mi) }; - GetMonitorInfo(MonitorFromWindow(hWindow, MONITOR_DEFAULTTOPRIMARY), &mi); - SetWindowLong(hWindow, GWL_STYLE, dwStyle & ~dwRmvFScrStyle); - WINDOWPLACEMENT wndpl = WindowPlacementFromInfo(hWindow, NULL, mode); - if (GetDoAnimateMinimize()) { - DrawAnimatedRects(hWindow, IDANI_CAPTION, &rcCurrent, &wndpl.rcNormalPosition); - } - SetWindowPlacement(hWindow, &wndpl); - SetWindowPos(hWindow, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, - mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, - SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - Settings.ShowMenubar = Settings.ShowToolbar = Settings.ShowStatusbar = false; - Settings.AlwaysOnTop = true; - s_bPrevFullScreenFlag = true; - } - SendWMSize(hWindow, NULL); - UpdateToolbar(); -} - - //============================================================================= // // ShowNotifyIcon() @@ -12389,7 +12354,6 @@ static HANDLE s_hEventObserverDone = INVALID_HANDLE_VALUE; static unsigned __stdcall FileChangeObserver(void * pArg) { - if (!pArg) { _endthreadex(0); return 0; diff --git a/src/Notepad3.h b/src/Notepad3.h index 7a5e17d1b..03739217c 100644 --- a/src/Notepad3.h +++ b/src/Notepad3.h @@ -8,7 +8,7 @@ * Global definitions and declarations * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * @@ -109,15 +109,14 @@ bool InitApplication(const HINSTANCE hInstance); //~bool InitToolbarWndClass(const HINSTANCE hInstance); HWND InitInstance(const HINSTANCE hInstance, LPCWSTR pszCmdLine, int nCmdShow); void CreateBars(HWND hwnd, HINSTANCE hInstance); -WININFO GetFactoryDefaultWndPos(const int flagsPos); -WININFO GetWinInfoByFlag(const int flagsPos); +WININFO GetFactoryDefaultWndPos(HWND hwnd, const int flagsPos); +WININFO GetWinInfoByFlag(HWND hwnd, const int flagsPos); int CountRunningInstances(); bool ActivatePrevInst(); bool LaunchNewInstance(HWND hwnd, LPCWSTR lpszParameter, LPCWSTR lpszFilePath); bool RelaunchMultiInst(); bool RelaunchElevated(LPCWSTR lpNewCmdLnArgs); bool DoElevatedRelaunch(EditFileIOStatus* pFioStatus, bool bAutoSaveOnRelaunch); -void SnapToWinInfoPos(HWND hwnd, const WININFO winInfo, SCREEN_MODE mode); void ShowNotifyIcon(HWND hwnd, bool bAdd); void SetNotifyIconTitle(HWND hwnd); void SetSaveDone(); diff --git a/src/Notepad3.rc b/src/Notepad3.rc index 0f5a6c0e8..5b4d7f58e 100644 --- a/src/Notepad3.rc +++ b/src/Notepad3.rc @@ -216,6 +216,9 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // After Win10 1903 upgrade, Ctrl+Alt+Shift+F hotkey is intercepted by File Explorer (issue #1609) // // +// -------------------------------------------------------------------------------------------------------------------- +// Reference: https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +// -------------------------------------------------------------------------------------------------------------------- IDR_MAINWND ACCELERATORS BEGIN diff --git a/src/Notepad3.ver b/src/Notepad3.ver index 2c24e1b3d..f608a517c 100644 --- a/src/Notepad3.ver +++ b/src/Notepad3.ver @@ -7,7 +7,7 @@ * Notepad3 version information * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * *******************************************************************************/ diff --git a/src/PathLib.c b/src/PathLib.c index f0458d447..49a634d3b 100644 --- a/src/PathLib.c +++ b/src/PathLib.c @@ -8,7 +8,7 @@ * Implementation for dynamic wide char Long Path handling * * Based on DynStrg module * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/PathLib.h b/src/PathLib.h index ae3afe8ec..58c6c7785 100644 --- a/src/PathLib.h +++ b/src/PathLib.h @@ -8,7 +8,7 @@ * Definition for dynamic wide char Long Path handling * * Based on DynStrg module * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Print.cpp b/src/Print.cpp index 22c1379ae..1b9f63b2f 100644 --- a/src/Print.cpp +++ b/src/Print.cpp @@ -10,7 +10,7 @@ * * * Mostly taken from SciTE, (c) Neil Hodgson * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/SciCall.h b/src/SciCall.h index db0d554e4..f1e1a560d 100644 --- a/src/SciCall.h +++ b/src/SciCall.h @@ -12,7 +12,7 @@ * The use of these inline wrapper functions with declared types will * * ensure that we get the benefit of the compiler's type checking. * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * @@ -195,6 +195,10 @@ DeclareSciCallV01(GetWordChars, GETWORDCHARS, char*, ptxt); DeclareSciCallV01(GetWhiteSpaceChars, GETWHITESPACECHARS, char*, ptxt); DeclareSciCallV01(GetPunctuationChars, GETPUNCTUATIONCHARS, char*, ptxt); +DeclareSciCallV2(SetRepresentation, SETREPRESENTATION, const char*, encChar, const char*, represent); +DeclareSciCallV2(SetRepresentationColour, SETREPRESENTATIONCOLOUR, const char*, encChar, COLORALPHAREF, colour); +DeclareSciCallV2(SetRepresentationAppearance, SETREPRESENTATIONAPPEARANCE, const char*, encChar, int, appear); + // Document Pointer Handling DeclareSciCallR0(GetDocPointer, GETDOCPOINTER, sptr_t); DeclareSciCallV01(SetDocPointer, SETDOCPOINTER, sptr_t, pdoc); diff --git a/src/StyleLexers/EditLexer.c b/src/StyleLexers/EditLexer.c index 7aab77e00..b1d8dee27 100644 --- a/src/StyleLexers/EditLexer.c +++ b/src/StyleLexers/EditLexer.c @@ -234,6 +234,10 @@ void Lexer_SetLexerSpecificProperties(const int lexerId) { //SciCall_SetProperty("lexer.sql.allow.dotted.word", "0"); break; + case SCLEX_MARKDOWN: + SciCall_SetProperty("lexer.markdown.header.eolfill", "1"); + break; + case SCLEX_NSIS: SciCall_SetProperty("nsis.ignorecase", "1"); break; diff --git a/src/StyleLexers/styleLexMARKDOWN.c b/src/StyleLexers/styleLexMARKDOWN.c index ab3a6b686..9e6721fe2 100644 --- a/src/StyleLexers/styleLexMARKDOWN.c +++ b/src/StyleLexers/styleLexMARKDOWN.c @@ -14,7 +14,7 @@ EDITLEXER lexMARKDOWN = { {SCE_MARKDOWN_LINE_BEGIN}, IDS_LEX_STR_63317, L"Line Begin", L"", L"" }, { {MULTI_STYLE(SCE_MARKDOWN_STRONG1,SCE_MARKDOWN_STRONG2,0,0)}, IDS_LEX_STR_63318, L"Strong", L"bold", L"" }, { {MULTI_STYLE(SCE_MARKDOWN_EM1,SCE_MARKDOWN_EM2,0,0)}, IDS_LEX_STR_63319, L"Emphasis", L"italic", L"" }, - { {SCE_MARKDOWN_HEADER1}, IDS_LEX_STR_63320, L"Header 1", L"bold; fore:#FFFFE2; back:#3D3DD3; eolfilled", L"" }, + { {SCE_MARKDOWN_HEADER1}, IDS_LEX_STR_63320, L"Header 1", L"bold; fore:#FFFFE2; back:#8BA4ED; eolfilled", L"" }, { {SCE_MARKDOWN_HEADER2}, IDS_LEX_STR_63321, L"Header 2", L"bold; fore:#336193; back:#9DCEFF; eolfilled", L"" }, { {SCE_MARKDOWN_HEADER3}, IDS_LEX_STR_63322, L"Header 3", L"bold; fore:#336193; back:#D9ECFF; eolfilled", L"" }, { {SCE_MARKDOWN_HEADER4}, IDS_LEX_STR_63323, L"Header 4", L"bold; fore:#336193; eolfilled", L"" }, diff --git a/src/StyleLexers/styleLexStandard.c b/src/StyleLexers/styleLexStandard.c index 42c8bd6a5..80f640875 100644 --- a/src/StyleLexers/styleLexStandard.c +++ b/src/StyleLexers/styleLexStandard.c @@ -20,7 +20,7 @@ EDITLEXER lexStandard = /* 9 */ { {_STYLE_GETSTYLEID(STY_CARET)}, IDS_LEX_STD_CARET, L"Caret (Color, Size 1-3)", L"", L"" }, /* 10 */ { {_STYLE_GETSTYLEID(STY_LONG_LN_MRK)}, IDS_LEX_STD_LONG_LN, L"Long Line Marker (Colors)", L"fore:#FFC000", L"" }, /* 11 */ { {_STYLE_GETSTYLEID(STY_X_LN_SPACE)}, IDS_LEX_STD_X_SPC, L"Extra Line Spacing (Size)", L"size:2", L"" }, - /* 12 */ { {_STYLE_GETSTYLEID(STY_BOOK_MARK)}, IDS_LEX_STD_BKMRK, L"Bookmarks and Folding (Colors, Size)", L"fore:#000000; back:#00DC00; alpha:100", L"" }, + /* 12 */ { {_STYLE_GETSTYLEID(STY_BOOK_MARK)}, IDS_LEX_STD_BKMRK, L"Bookmarks and Folding (Colors, Size)", L"fore:#00DC00; alpha:100", L"" }, /* 13 */ { {_STYLE_GETSTYLEID(STY_MARK_OCC)}, IDS_LEX_STR_63262, L"Mark Occurrences (Indicator)", L"fore:#3399FF; alpha:60; alpha2:60; indic_roundbox", L"" }, /* 14 */ { {_STYLE_GETSTYLEID(STY_URL_HOTSPOT)}, IDS_LEX_STR_63264, L"Hyperlink Hotspots", L"fore:#0000E0; back:#0060B0; indic_plain", L"" }, /* 15 */ { {_STYLE_GETSTYLEID(STY_UNICODE_HOTSPOT)}, IDS_LEX_STR_63367, L"Unicode-Point Hover", L"fore:#00FA00; alpha:60; alpha2:180; indic_compositionthick", L""}, @@ -50,7 +50,7 @@ EDITLEXER lexStandard2nd = /* 9 */ { {_STYLE_GETSTYLEID(STY_CARET)}, IDS_LEX_2ND_CARET, L"2nd Caret (Color, Size 1-3)", L"", L"" }, /* 10 */ { {_STYLE_GETSTYLEID(STY_LONG_LN_MRK)}, IDS_LEX_2ND_LONG_LN, L"2nd Long Line Marker (Colors)", L"fore:#FFC000", L"" }, /* 11 */ { {_STYLE_GETSTYLEID(STY_X_LN_SPACE)}, IDS_LEX_2ND_X_SPC, L"2nd Extra Line Spacing (Size)", L"", L"" }, - /* 12 */ { {_STYLE_GETSTYLEID(STY_BOOK_MARK)}, IDS_LEX_2ND_BKMRK, L"2nd Bookmarks and Folding (Colors, Size)", L"charset:2; fore:#000000; back:#00DC00; case:U; alpha:100", L"" }, + /* 12 */ { {_STYLE_GETSTYLEID(STY_BOOK_MARK)}, IDS_LEX_2ND_BKMRK, L"2nd Bookmarks and Folding (Colors, Size)", L"charset:2; fore:#00DC00; case:U; alpha:100", L"" }, /* 13 */ { {_STYLE_GETSTYLEID(STY_MARK_OCC)}, IDS_LEX_STR_63263, L"2nd Mark Occurrences (Indicator)", L"fore:#0000FF; alpha:60; alpha2:60; indic_box", L"" }, /* 14 */ { {_STYLE_GETSTYLEID(STY_URL_HOTSPOT)}, IDS_LEX_STR_63265, L"2nd Hyperlink Hotspots", L"fore:#00D000; back:#009C00; alpha:180; indic_compositionthin", L"" }, /* 15 */ { {_STYLE_GETSTYLEID(STY_UNICODE_HOTSPOT)}, IDS_LEX_STR_63368, L"2nd Unicode-Point Hover", L"fore:#0000FA; alpha:60; alpha2:180; indic_compositionthick", L""}, diff --git a/src/Styles.c b/src/Styles.c index abbdbc9f8..6732d0391 100644 --- a/src/Styles.c +++ b/src/Styles.c @@ -652,7 +652,7 @@ float Style_GetCurrentLexerFontSize() //============================================================================= // -// Style_RgbAlpha() +// Style_RgbAlpha() - Simulate Translucency // int Style_RgbAlpha(int rgbFore, int rgbBack, int alpha) { @@ -1527,6 +1527,7 @@ void Style_SetLexer(HWND hwnd, PEDITLEXER pLexNew) iValue = clampi(iValue, 1, 12); StringCchPrintf(wchSpecificStyle, COUNTOF(wchSpecificStyle), L"size:%i", iValue); } + //@@@SciCall_SetWhiteSpaceSize(MulDiv(iValue, SciCall_GetZoom(), 100)); // needs update on zoom SciCall_SetWhiteSpaceSize(iValue); // whitespace colors @@ -1540,9 +1541,15 @@ void Style_SetLexer(HWND hwnd, PEDITLEXER pLexNew) StringCchCat(wchSpecificStyle, COUNTOF(wchSpecificStyle), wch); } SciCall_SetElementColour(SC_ELEMENT_WHITE_SPACE, RGBxA(rgb, iValue)); + SciCall_SetRepresentationColour("\r", RGBxA(rgb, iValue)); + SciCall_SetRepresentationColour("\n", RGBxA(rgb, iValue)); + SciCall_SetRepresentationColour("\r\n", RGBxA(rgb, iValue)); } else { SciCall_ResetElementColour(SC_ELEMENT_WHITE_SPACE); + SciCall_SetRepresentationColour("\r", SciCall_GetElementColour(SC_ELEMENT_WHITE_SPACE)); + SciCall_SetRepresentationColour("\n", SciCall_GetElementColour(SC_ELEMENT_WHITE_SPACE)); + SciCall_SetRepresentationColour("\r\n", SciCall_GetElementColour(SC_ELEMENT_WHITE_SPACE)); } rgb = RGB(0, 0, 0); @@ -1570,12 +1577,6 @@ void Style_SetLexer(HWND hwnd, PEDITLEXER pLexNew) // current line background Style_HighlightCurrentLine(hwnd, Settings.HighlightCurrentLine); - // bookmark line or marker - Style_UpdateBookmarkMargin(hwnd); - - // Change History - Style_UpdateChangeHistoryMargin(Globals.hwndEdit); - // Hyperlink (URL) indicators Style_SetUrlHotSpot(hwnd); @@ -1714,10 +1715,10 @@ void Style_SetLexer(HWND hwnd, PEDITLEXER pLexNew) } if (bFocusedView) { - EditToggleView(Globals.hwndEdit); + EditToggleView(hwnd); } - UpdateMargins(true); + Style_UpdateAllMargins(hwnd, true); EndWaitCursor(); @@ -2009,41 +2010,58 @@ void Style_HighlightCurrentLine(HWND hwnd, int iHiLitCurLn) //============================================================================= // -// _GetMarkerMarginWidth() +// Style_UpdateLineNumberMargin() // -static int _GetMarkerMarginWidth(HWND hwnd, const float scale) +void Style_UpdateLineNumberMargin(const bool bForce) { - float ftotal = 0.0f; - float const fbase = Style_GetBaseFontSize(); + static bool bShowLnNums = false; + static DocLn prevLineCount = -1LL; - float fSize = fbase; - Style_StrGetSizeFloatEx(GetCurrentStdLexer()->Styles[STY_MARGIN].szValue, &fSize); // linenumber - ftotal += fSize; + DocLn const currLineCount = SciCall_GetLineCount(); - fSize = fbase; - Style_StrGetSizeFloatEx(GetCurrentStdLexer()->Styles[STY_BOOK_MARK].szValue, &fSize); // settings - ftotal += fSize; + if (!bForce && (currLineCount == prevLineCount) && (bShowLnNums == Settings.ShowLineNumbers)) { + return; + } - float const zoomPercent = (float)SciCall_GetZoom(); - return ScaleFloatToDPI(hwnd, (ftotal * zoomPercent * scale) / 100.0f); + if (Settings.ShowLineNumbers) { + static char chLines[32] = { '\0' }; + StringCchPrintfA(chLines, COUNTOF(chLines), "_%td", (size_t)currLineCount); + int const iLineMarginWidthFit = SciCall_TextWidth(STYLE_LINENUMBER, chLines); + int const iLineMarginWidthNow = SciCall_GetMarginWidthN(MARGIN_SCI_LINENUM); + if (iLineMarginWidthNow != iLineMarginWidthFit) { + SciCall_SetMarginWidthN(MARGIN_SCI_LINENUM, iLineMarginWidthFit); + } + } + else { + SciCall_SetMarginWidthN(MARGIN_SCI_LINENUM, 0); + } + + bShowLnNums = Settings.ShowLineNumbers; + prevLineCount = currLineCount; } + //============================================================================= // -// Style_UpdateFoldingMargin() +// _GetMarkerMarginWidth() // -void Style_UpdateFoldingMargin(HWND hwnd, bool bShowMargin) +static int _GetMarkerMarginWidth(HWND hwnd, LPCWSTR styleStrg, const float fScale) { - SciCall_SetMarginWidthN(MARGIN_SCI_FOLDING, (bShowMargin ? _GetMarkerMarginWidth(hwnd, 0.5f) : 0)); + UNREFERENCED_PARAMETER(hwnd); + float fSize = (float)SciCall_TextWidth(STYLE_LINENUMBER, "__"); // 2x underscore + Style_StrGetSizeFloatEx(styleStrg, &fSize); + return lroundf(fSize * fScale); } + //============================================================================= // // Style_UpdateBookmarkMargin() // void Style_UpdateBookmarkMargin(HWND hwnd) { - SciCall_SetMarginWidthN(MARGIN_SCI_BOOKMRK, (Settings.ShowBookmarkMargin ? _GetMarkerMarginWidth(hwnd, 0.7f) : 0)); + int const size = _GetMarkerMarginWidth(hwnd, GetCurrentStdLexer()->Styles[STY_BOOK_MARK].szValue, 1.0f); + SciCall_SetMarginWidthN(MARGIN_SCI_BOOKMRK, (Settings.ShowBookmarkMargin ? size : 0)); } @@ -2053,8 +2071,36 @@ void Style_UpdateBookmarkMargin(HWND hwnd) // void Style_UpdateChangeHistoryMargin(HWND hwnd) { + int const size = _GetMarkerMarginWidth(hwnd, GetCurrentStdLexer()->Styles[STY_BOOK_MARK].szValue, 1.0f); bool const bShowMargin = (Settings.ChangeHistoryMode & SC_CHANGE_HISTORY_MARKERS); - SciCall_SetMarginWidthN(MARGIN_SCI_CHGHIST, (bShowMargin ? _GetMarkerMarginWidth(hwnd, 0.7f) : 0)); + SciCall_SetMarginWidthN(MARGIN_SCI_CHGHIST, (bShowMargin ? size : 0)); +} + + +//============================================================================= +// +// Style_UpdateFoldingMargin() +// +void Style_UpdateFoldingMargin(HWND hwnd, bool bShowMargin) +{ + int const size = _GetMarkerMarginWidth(hwnd, GetCurrentStdLexer()->Styles[STY_BOOK_MARK].szValue, 0.8f); + SciCall_SetMarginWidthN(MARGIN_SCI_FOLDING, (bShowMargin ? size : 0)); +} + + +//============================================================================= +// +// UpdateMargins() +// +// +void Style_UpdateAllMargins(HWND hwnd, const bool bForce) +{ + Style_UpdateLineNumberMargin(bForce); + if (bForce) { + Style_UpdateBookmarkMargin(hwnd); + Style_UpdateChangeHistoryMargin(hwnd); + Style_UpdateFoldingMargin(hwnd, (FocusedView.CodeFoldingAvailable && FocusedView.ShowCodeFolding)); + } } @@ -2066,6 +2112,7 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE { Style_SetStyles(hwnd, STYLE_LINENUMBER, lpszStyle, Style_GetBaseFontSize()); // line numbers + int alpha; COLORREF colorRead; // foreground @@ -2081,15 +2128,6 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE } COLORREF const clrMarginBack = colorRead; - COLORREF fldHiLight = clrLineNumFore; - const WCHAR* wchHighlightStyleStrg = GetCurrentStdLexer()->Styles[STY_SEL_TXT].szValue; - Style_StrGetColor(wchHighlightStyleStrg, FOREGROUND_LAYER, &fldHiLight, NULL, true); - - COLORREF clrFoldMarginBack = clrMarginBack; - const WCHAR* wchDefaultStyleStrg = GetCurrentStdLexer()->Styles[STY_DEFAULT].szValue; - Style_StrGetColor(wchDefaultStyleStrg, BACKGROUND_LAYER, &clrFoldMarginBack, NULL, true); - - // --- Line Numbers --- SciCall_StyleSetBack(STYLE_LINENUMBER, clrMarginBack); SciCall_SetMarginBackN(MARGIN_SCI_LINENUM, clrMarginBack); @@ -2106,17 +2144,19 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE // --- Bookmarks --- LPCWSTR const wchBookMarkStyleStrg = GetCurrentStdLexer()->Styles[STY_BOOK_MARK].szValue; - colorRead = clrLineNumFore; + colorRead = clrLineNumFore; // bookmark Style_StrGetColor(wchBookMarkStyleStrg, FOREGROUND_LAYER, &colorRead, NULL, false); - COLORREF const clrBookMarkFore = colorRead; - colorRead = clrMarginBack; - Style_StrGetColor(wchBookMarkStyleStrg, BACKGROUND_LAYER, &colorRead, NULL, false); - // adjust background color by alpha in case of show margin - int alpha; Style_StrGetAlpha(wchBookMarkStyleStrg, &alpha, SC_ALPHA_OPAQUE, true); - COLORREF const clrBookMarkBack = Style_RgbAlpha(colorRead, clrMarginBack, alpha); + int const bookmarkAlpha = alpha; + + colorRead = clrMarginBack; // folding signs + // document background as default: + Style_StrGetColor(GetCurrentStdLexer()->Styles[STY_DEFAULT].szValue, BACKGROUND_LAYER, &colorRead, NULL, true); + // if defined, use bookmark background color + Style_StrGetColor(wchBookMarkStyleStrg, BACKGROUND_LAYER, &colorRead, NULL, false); + COLORREF const clrFoldMarginBack = colorRead; int strokeWidth = FW_DONTCARE; if (!Style_StrGetWeightValue(lpszStyle, &strokeWidth)) { @@ -2126,8 +2166,10 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE SciCall_MarkerDefine(MARKER_NP3_BOOKMARK, SC_MARK_VERTICALBOOKMARK); // SC_MARK_BOOKMARK/SC_MARK_SHORTARROW SciCall_MarkerSetStrokeWidth(MARKER_NP3_BOOKMARK, strokeWidth); - SciCall_MarkerSetForeTranslucent(MARKER_NP3_BOOKMARK, RGBxA(clrBookMarkFore, SC_ALPHA_OPAQUE)); - SciCall_MarkerSetBackTranslucent(MARKER_NP3_BOOKMARK, RGBxA(clrBookMarkBack, alpha)); + SciCall_MarkerSetAlpha(MARKER_NP3_BOOKMARK, bookmarkAlpha); // if drawn in content area + SciCall_MarkerSetForeTranslucent(MARKER_NP3_BOOKMARK, RGBxA(clrLineNumFore, bookmarkAlpha)); //~clrBookMarkFore + //~SciCall_MarkerSetBack(MARKER_NP3_BOOKMARK, Style_RgbAlpha(clrBookMarkFore, clrMarginBack, bookmarkAlpha)); + SciCall_MarkerSetBackTranslucent(MARKER_NP3_BOOKMARK, RGBxA(clrBookMarkFore, bookmarkAlpha)); // occurrence bookmarker bool const visible = Settings.MarkOccurrencesBookmark; @@ -2143,8 +2185,9 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE for (int m = MARKER_NP3_1; m < MARKER_NP3_BOOKMARK; ++m) { SciCall_MarkerDefine(m, (Settings.FocusViewMarkerMode & FVMM_LN_BACKGR) ? SC_MARK_BACKGROUND : SC_MARK_BOOKMARK); Style_StrGetColor(WordBookMarks[m], BACKGROUND_LAYER, &color, NULL, true); + SciCall_MarkerSetAlpha(m, bookmarkAlpha); // if drawn in content area SciCall_MarkerSetForeTranslucent(m, RGBxA(color, SC_ALPHA_OPAQUE)); - SciCall_MarkerSetBackTranslucent(m, RGBxA(color, alpha)); // 'alpha' no meaning for SC_MARK_BACKGROUND + SciCall_MarkerSetBackTranslucent(m, RGBxA(color, bookmarkAlpha)); // 'alpha' no meaning for SC_MARK_BACKGROUND } SciCall_SetMarginBackN(MARGIN_SCI_BOOKMRK, clrMarginBack); @@ -2157,7 +2200,7 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE SciCall_SetMarginSensitiveN(MARGIN_SCI_CHGHIST, true); const WCHAR* const wchChgHistMrkModifiedStyleStrg = GetCurrentStdLexer()->Styles[STY_CHGHIST_MODIFIED].szValue; - colorRead = clrBookMarkFore; + colorRead = clrLineNumFore; if (Style_StrGetColor(wchChgHistMrkModifiedStyleStrg, FOREGROUND_LAYER, &colorRead, NULL, false)) { SciCall_MarkerSetFore(SC_MARKNUM_HISTORY_MODIFIED, colorRead); } @@ -2168,11 +2211,11 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE // TODO: alpha/translucent/layer in print mode ? //Style_StrGetAlpha(wchChgHistMrkModifiedStyleStrg, &alpha, SC_ALPHA_OPAQUE, true); - //COLORREF const rgbAlpha = Style_RgbAlpha(colorRead, clrMarginBack, alpha); //SciCall_MarkerSetAlpha(SC_MARKNUM_HISTORY_MODIFIED, alpha); + // COLORREF const rgbAlpha = Style_RgbAlpha(colorRead, clrMarginBack, alpha); const WCHAR* const wchChgHistMrkSavedStyleStrg = GetCurrentStdLexer()->Styles[STY_CHGHIST_SAVED].szValue; - colorRead = clrBookMarkFore; + colorRead = clrLineNumFore; if (Style_StrGetColor(wchChgHistMrkSavedStyleStrg, FOREGROUND_LAYER, &colorRead, NULL, false)) { SciCall_MarkerSetFore(SC_MARKNUM_HISTORY_SAVED, colorRead); } @@ -2180,9 +2223,10 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE if (Style_StrGetColor(wchChgHistMrkSavedStyleStrg, BACKGROUND_LAYER, &colorRead, NULL, false)) { SciCall_MarkerSetBack(SC_MARKNUM_HISTORY_SAVED, colorRead); } + //SciCall_MarkerSetStrokeWidth(SC_MARKNUM_HISTORY_SAVED, strokeWidth); const WCHAR* const wchChgHistMrkRev2OrgStyleStrg = GetCurrentStdLexer()->Styles[STY_CHGHIST_REV_TO_ORG].szValue; - colorRead = clrBookMarkFore; + colorRead = clrLineNumFore; if (Style_StrGetColor(wchChgHistMrkRev2OrgStyleStrg, FOREGROUND_LAYER, &colorRead, NULL, false)) { SciCall_MarkerSetFore(SC_MARKNUM_HISTORY_REVERTED_TO_ORIGIN, colorRead); } @@ -2190,9 +2234,10 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE if (Style_StrGetColor(wchChgHistMrkRev2OrgStyleStrg, BACKGROUND_LAYER, &colorRead, NULL, false)) { SciCall_MarkerSetBack(SC_MARKNUM_HISTORY_REVERTED_TO_ORIGIN, colorRead); } + //SciCall_MarkerSetStrokeWidth(SC_MARKNUM_HISTORY_REVERTED_TO_ORIGIN, strokeWidth); const WCHAR* const wchChgHistMrkRev2ModStyleStrg = GetCurrentStdLexer()->Styles[STY_CHGHIST_REV_TO_MOD].szValue; - colorRead = clrBookMarkFore; + colorRead = clrLineNumFore; if (Style_StrGetColor(wchChgHistMrkRev2ModStyleStrg, FOREGROUND_LAYER, &colorRead, NULL, false)) { SciCall_MarkerSetFore(SC_MARKNUM_HISTORY_REVERTED_TO_MODIFIED, colorRead); } @@ -2200,16 +2245,12 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE if (Style_StrGetColor(wchChgHistMrkRev2ModStyleStrg, BACKGROUND_LAYER, &colorRead, NULL, false)) { SciCall_MarkerSetBack(SC_MARKNUM_HISTORY_REVERTED_TO_MODIFIED, colorRead); } - - Style_UpdateChangeHistoryMargin(Globals.hwndEdit); - + //SciCall_MarkerSetStrokeWidth(SC_MARKNUM_HISTORY_REVERTED_TO_MODIFIED, strokeWidth); // --- Code folding --- - SciCall_SetMarginBackN(MARGIN_SCI_FOLDING, clrMarginBack); SciCall_SetMarginSensitiveN(MARGIN_SCI_FOLDING, true); - int fldStyleMrk = SC_CASE_LOWER; Style_StrGetCase(wchBookMarkStyleStrg, &fldStyleMrk); if (fldStyleMrk == SC_CASE_UPPER) { // circle style @@ -2229,7 +2270,6 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE SciCall_MarkerDefine(SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED); SciCall_MarkerDefine(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER); } - static const int FoldMarkerID[] = { SC_MARKNUM_FOLDEROPEN, SC_MARKNUM_FOLDER, @@ -2240,16 +2280,24 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE SC_MARKNUM_FOLDERMIDTAIL }; + colorRead = clrLineNumFore; + const WCHAR* wchHighlightStyleStrg = GetCurrentStdLexer()->Styles[STY_SEL_TXT].szValue; + Style_StrGetColor(wchHighlightStyleStrg, FOREGROUND_LAYER, &colorRead, NULL, true); + COLORREF const fldHiLight = colorRead; + for (int i = 0; i < COUNTOF(FoldMarkerID); ++i) { - SciCall_MarkerSetFore(FoldMarkerID[i], clrBookMarkBack); // (!) - SciCall_MarkerSetBack(FoldMarkerID[i], clrBookMarkFore); // (!) + SciCall_MarkerSetForeTranslucent(FoldMarkerID[i], RGBxA(clrFoldMarginBack, SC_ALPHA_OPAQUE)); // (!) + SciCall_MarkerSetBackTranslucent(FoldMarkerID[i], RGBxA(clrLineNumFore, SC_ALPHA_OPAQUE)); // (!) //~clrBookMarkForeAlpha SciCall_MarkerSetBackSelected(FoldMarkerID[i], fldHiLight); + SciCall_MarkerSetStrokeWidth(FoldMarkerID[i], strokeWidth); } SciCall_MarkerEnableHighlight(true); // highlight folding block // background - SciCall_SetFoldMarginColour(true, clrFoldMarginBack); // background + //~SciCall_SetMarginBackN(MARGIN_SCI_FOLDING, clrMarginBack); // no effect + SciCall_SetFoldMarginColour(true, clrFoldMarginBack); // background SciCall_SetFoldMarginHiColour(true, clrFoldMarginBack); // (!) + //SciCall_FoldDisplayTextSetStyle(SC_FOLDDISPLAYTEXT_BOXED); //SciCall_SetDefaultFoldDisplayText("..."); @@ -2272,8 +2320,7 @@ void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle) /// iStyle == STYLE_LINENUMBE } // set width - Style_UpdateBookmarkMargin(hwnd); - Style_UpdateFoldingMargin(hwnd, (FocusedView.CodeFoldingAvailable && FocusedView.ShowCodeFolding)); + Style_UpdateAllMargins(hwnd, true); } diff --git a/src/Styles.h b/src/Styles.h index ec9985a05..7ea099899 100644 --- a/src/Styles.h +++ b/src/Styles.h @@ -8,7 +8,7 @@ * Scintilla Style Management * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * @@ -63,9 +63,11 @@ void Style_SetUrlHotSpot(HWND hwnd); void Style_SetInvisible(HWND hwnd, bool); //void Style_SetReadonly(HWND hwnd, bool); void Style_HighlightCurrentLine(HWND hwnd, int); -void Style_UpdateFoldingMargin(HWND hwnd, bool bShowMargin); +void Style_UpdateLineNumberMargin(const bool bForce); void Style_UpdateBookmarkMargin(HWND hwnd); void Style_UpdateChangeHistoryMargin(HWND hwnd); +void Style_UpdateFoldingMargin(HWND hwnd, bool bShowMargin); +void Style_UpdateAllMargins(HWND hwnd, const bool bForce); void Style_SetMargin(HWND hwnd, LPCWSTR lpszStyle); bool Style_SetLexerFromFile(HWND hwnd,const HPATHL hpath); bool Style_MaybeBinaryFile(HWND hwnd, const HPATHL hpath); diff --git a/src/TypeDefs.h b/src/TypeDefs.h index 48112d03b..4594cf4c1 100644 --- a/src/TypeDefs.h +++ b/src/TypeDefs.h @@ -7,7 +7,7 @@ * * * TypeDefs.h * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/Version.h b/src/Version.h index 91cb7615a..749c26fba 100644 --- a/src/Version.h +++ b/src/Version.h @@ -7,7 +7,7 @@ * Version.h * * Based on code from Notepad2-mod, (c) XhmikosR 2010-2015 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://www.rizonesoft.com * * * * * @@ -42,8 +42,8 @@ #pragma message("Release Build: " _STRG(VERSION_FILEVERSION_LONG)) #endif -#define VERSION_LEGALCOPYRIGHT "Copyright © 2008-2022 Rizonesoft" -//#define VERSION_LEGALCOPYRIGHT_LONG "© Rizonesoft 2008-2022" +#define VERSION_LEGALCOPYRIGHT "Copyright © 2008-2023 Rizonesoft" +//#define VERSION_LEGALCOPYRIGHT_LONG "© Rizonesoft 2008-2023" #define VERSION_AUTHORNAME "© Rizonesoft" #define VERSION_WEBPAGEDISPLAY "https://www.rizonesoft.com" #define VERSION_COMPANYNAME "© Rizonesoft" diff --git a/src/VersionEx.h b/src/VersionEx.h index 5cb34511c..8db880c77 100644 --- a/src/VersionEx.h +++ b/src/VersionEx.h @@ -7,8 +7,8 @@ #define APPNAME Notepad3 #define SAPPNAME "Notepad3" #define VERSION_MAJOR 5 -#define VERSION_MINOR 22 -#define VERSION_REV 1228 +#define VERSION_MINOR 23 +#define VERSION_REV 101 #define VERSION_BUILD 1 #define SCINTILLA_VER 532 #define LEXILLA_VER 521 diff --git a/src/_backlog/AccelKeys.c b/src/_backlog/AccelKeys.c index f347d55fa..2bf478efe 100644 --- a/src/_backlog/AccelKeys.c +++ b/src/_backlog/AccelKeys.c @@ -8,7 +8,7 @@ * Load Accelerator Keys at Runtime * * * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * *******************************************************************************/ diff --git a/src/_backlog/AccelKeys.h b/src/_backlog/AccelKeys.h index 70a1c822c..927dc928b 100644 --- a/src/_backlog/AccelKeys.h +++ b/src/_backlog/AccelKeys.h @@ -7,7 +7,7 @@ * AccelKeys.h * * Load Accelerator Keys at Runtime * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/src/ced/ced/_tellenc.hpp b/src/ced/ced/_tellenc.hpp index 9b922cf62..299710aeb 100644 --- a/src/ced/ced/_tellenc.hpp +++ b/src/ced/ced/_tellenc.hpp @@ -8,7 +8,7 @@ S/***************************************************************************** * Encoding detector tables * * Based on code from Notepad2, (c) Florian Balmer 1996-2011 * * * -* (c) Rizonesoft 2008-2022 * +* (c) Rizonesoft 2008-2023 * * https://rizonesoft.com * * * * * diff --git a/test/test_files/StyleLexers/styleLexCPP/Config.cpp b/test/test_files/StyleLexers/styleLexCPP/Config.cpp index 5a4f0ef6d..66365521f 100644 --- a/test/test_files/StyleLexers/styleLexCPP/Config.cpp +++ b/test/test_files/StyleLexers/styleLexCPP/Config.cpp @@ -13,6 +13,17 @@ addindex // TODO : fkdlkldfdl // ---------------------------------------------------------------------------- +namespace { + +1 +2 +3 +5 +4 +6 +7 +8 +9 extern "C" { #include "Version.h" @@ -477,4 +488,24540 @@ extern "C" bool FindIniFile() } //============================================================================= +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= + +extern "C" { +#include "Version.h" +#include "Helpers.h" +#include "Styles.h" +#include "Dialogs.h" +#include "Encoding.h" +#include "Notepad3.h" +#include "resource.h" +} + +extern "C" const int g_FontQuality[4]; +extern "C" WININFO s_WinInfo; +extern "C" WININFO s_DefWinInfo; + +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1; +extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2; + +extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT]; +extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT]; +extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT]; +extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT]; +extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT]; + +extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH]; +extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH]; + +extern "C" bool s_bEnableSaveSettings; +extern "C" int s_iToolBarTheme; + +extern "C" bool s_flagPosParam; +extern "C" int s_flagWindowPos; +extern "C" int s_flagReuseWindow; +extern "C" int s_flagSingleFileInstance; +extern "C" int s_flagMultiFileArg; +extern "C" int s_flagShellUseSystemMRU; +extern "C" int s_flagPrintFileAndLeave; + + +// ---------------------------------------------------------------------------- + +#include "SimpleIni.h" +#include "Config.h" + +// ============================================================================ + +static bool const s_bIsUTF8 = true; +static bool const s_bUseMultiKey = false; +static bool const s_bUseMultiLine = false; +static bool const s_bSetSpaces = false; + +// ---------------------------------------------------------------------------- + +static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS; + +// ---------------------------------------------------------------------------- + +#define SI_SUCCESS(RC) ((RC) >= SI_OK) + +// ============================================================================ + +static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + + +extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.Reset(); + SI_Error const rc = s_INI.LoadFile(lpIniFilePath); + return SI_SUCCESS(rc); +} + +extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath) +{ + s_INI.SetSpaces(s_bSetSpaces); + SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true); + if (SI_SUCCESS(rc)) { + s_INI.Reset(); // done + } + return SI_SUCCESS(rc); +} + +extern "C" void ReleaseIniFile() +{ + s_INI.Reset(); +} + + +//============================================================================= +// +// Manipulation of (cached) ini file +// +//============================================================================= + + +extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, + s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + bool bHasMultiple = false; + int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; +} +// ============================================================================ + + +extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault) +{ + bool bHasMultiple = false; + double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple); + //assert(!bHasMultiple); + return dValue; +} +// ============================================================================ + + +extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + bool bHasMultiple = false; + bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; +} +// ============================================================================ + + +extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue) +{ + SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty); +} +// ============================================================================ + + +extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty) +{ + + bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty); + if (!bRemoveEmpty) { + SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr); + return SI_SUCCESS(rc); + } + return ok; +} +// ============================================================================ + + +extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty) +{ + size_t const len = StringCchLen(lpPrefix, 0); + + CSimpleIni::TNamesDepend Sections; + s_INI.GetAllSections(Sections); + for (const auto& section : Sections) + { + if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0) + { + s_INI.Delete(section.pItem, nullptr, bRemoveEmpty); + } + } + return true; +} +// ============================================================================ + + +// ============================================================================ +// ============================================================================ + + +extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, + LPWSTR lpReturnedString, size_t cchReturnedString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple)); + //assert(!bHasMultiple); + } + return StringCchLenW(lpReturnedString, cchReturnedString); +} +// ============================================================================ + + +extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey); + rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL; + + if (SI_SUCCESS(rc)) { + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple); + //assert(!bHasMultiple); + return iValue; + } + return iDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error const rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + bool bHasMultiple = false; + bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple); + //assert(!bHasMultiple); + return bValue; + } + return bDefault; +} +// ============================================================================ + + +extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) { + Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty) +{ + CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine); + SI_Error rc = Ini.LoadFile(lpFilePath); + if (SI_SUCCESS(rc)) + { + Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty); + Ini.SetSpaces(s_bSetSpaces); + rc = Ini.SaveFile(Globals.IniFile, true); + } + return SI_SUCCESS(rc); +} +// ============================================================================ + + +//============================================================================= +// +// _CheckIniFile() +// +static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded)); + + if (PathIsRelative(tchFileExpanded)) + { + WCHAR tchBuild[MAX_PATH] = { L'\0' }; + // program directory + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // sub directory (.\np3\) + StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule); + PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild)); + StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\"); + StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + // Application Data (%APPDATA%) + if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + // Home (%HOMEPATH%) user's profile dir + if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) { + PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded); + if (PathFileExists(tchBuild)) { + StringCchCopy(lpszFile, MAX_PATH, tchBuild); + return true; + } + } + //~// in general search path + //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) { + //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild); + //~ return true; + //~} + } + else if (PathFileExists(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule) +{ + WCHAR tch[MAX_PATH] = { L'\0' }; + if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) { + if (_CheckIniFile(tch, lpszModule)) { + StringCchCopy(lpszFile, MAX_PATH, tch); + return true; + } + WCHAR tchFileExpanded[MAX_PATH] = { L'\0' }; + ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded)); + if (PathIsRelative(tchFileExpanded)) { + StringCchCopy(lpszFile, MAX_PATH, lpszModule); + StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded); + return true; + } + StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded); + return true; + } + return false; +} +// ============================================================================ + + +extern "C" bool FindIniFile() +{ + bool bFound = false; + WCHAR tchPath[MAX_PATH] = { L'\0' }; + WCHAR tchModule[MAX_PATH] = { L'\0' }; + + GetModuleFileName(NULL, tchModule, COUNTOF(tchModule)); + + // set env path to module dir + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath); + + if (StrIsNotEmpty(Globals.IniFile)) { + if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) { + return bFound; + } + if (!_CheckIniFile(Globals.IniFile, tchModule)) { + ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile)); + if (PathIsRelative(Globals.IniFile)) { + StringCchCopy(tchPath, COUNTOF(tchPath), tchModule); + PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath)); + PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile); + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + } + } + else { + StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule)); + PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini"); + + bFound = _CheckIniFile(tchPath, tchModule); + + if (!bFound) { + StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini"); + bFound = _CheckIniFile(tchPath, tchModule); + } + + if (bFound) + { + // allow two redirections: administrator -> user -> custom + if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule)) + { + _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule); + } + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath); + } + else { + StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule); + PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini"); + } + } + + NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false); + + return bFound; +} +//============================================================================= diff --git a/themes/b&w/16/Toolbar.bmp b/themes/b&w/16/Toolbar.bmp new file mode 100644 index 000000000..572bc9b9a Binary files /dev/null and b/themes/b&w/16/Toolbar.bmp differ diff --git a/themes/std_scaled/16/Toolbar.bmp b/themes/std_scaled/16/Toolbar.bmp new file mode 100644 index 000000000..eb5b3d197 Binary files /dev/null and b/themes/std_scaled/16/Toolbar.bmp differ diff --git a/themes/std_scaled/16/ToolbarDisabled.bmp b/themes/std_scaled/16/ToolbarDisabled.bmp new file mode 100644 index 000000000..86d6e2cb9 Binary files /dev/null and b/themes/std_scaled/16/ToolbarDisabled.bmp differ diff --git a/themes/std_scaled/16/ToolbarHot.bmp b/themes/std_scaled/16/ToolbarHot.bmp new file mode 100644 index 000000000..4490effec Binary files /dev/null and b/themes/std_scaled/16/ToolbarHot.bmp differ diff --git a/themes/std_scaled/24/Toolbar2.bmp b/themes/std_scaled/24/Toolbar2.bmp new file mode 100644 index 000000000..93c59366f Binary files /dev/null and b/themes/std_scaled/24/Toolbar2.bmp differ diff --git a/themes/std_scaled/24/Toolbar2Disabled.bmp b/themes/std_scaled/24/Toolbar2Disabled.bmp new file mode 100644 index 000000000..b3db4cbd2 Binary files /dev/null and b/themes/std_scaled/24/Toolbar2Disabled.bmp differ diff --git a/themes/std_scaled/24/Toolbar2Hot.bmp b/themes/std_scaled/24/Toolbar2Hot.bmp new file mode 100644 index 000000000..c88d9518d Binary files /dev/null and b/themes/std_scaled/24/Toolbar2Hot.bmp differ diff --git a/themes/std_scaled_48/Toolbar2Disabled_48.bmp b/themes/std_scaled/48/Toolbar2Disabled_48.bmp similarity index 100% rename from themes/std_scaled_48/Toolbar2Disabled_48.bmp rename to themes/std_scaled/48/Toolbar2Disabled_48.bmp diff --git a/themes/std_scaled_48/Toolbar2Hot_48.bmp b/themes/std_scaled/48/Toolbar2Hot_48.bmp similarity index 100% rename from themes/std_scaled_48/Toolbar2Hot_48.bmp rename to themes/std_scaled/48/Toolbar2Hot_48.bmp diff --git a/themes/std_scaled_48/Toolbar2_48.bmp b/themes/std_scaled/48/Toolbar2_48.bmp similarity index 100% rename from themes/std_scaled_48/Toolbar2_48.bmp rename to themes/std_scaled/48/Toolbar2_48.bmp