From e368c67f2d499b314636c1ae93c835cb86f16816 Mon Sep 17 00:00:00 2001 From: adonais Date: Fri, 1 Dec 2023 17:36:47 +0800 Subject: [PATCH] Release 4.0.8 version --- conf/conf.d/eu_accel.lua | 10 +- conf/conf.d/eu_conf.lua | 10 +- conf/conf.d/eu_core.lua | 5 + conf/conf.d/eu_evaluation.lua | 15 +- conf/conf.d/eu_sci.lua | 6 + conf/conf.d/eu_theme.lua | 13 +- locales/src/en-us.rc | 33 +- locales/src/zh-cn.rc | 25 +- plugins/pdfview/np_pdfviewer.c | 2 + plugins/winexy/np_winexy.c | 212 +- plugins/xtool/xtool.c | 27 + share/changelog | 11 + share/example_build.sh | 6 +- src/3rdparty/luajit/src/jit/dis_arm64.lua | 3 +- src/3rdparty/luajit/src/lj_asm_arm.h | 28 +- src/3rdparty/luajit/src/lj_asm_arm64.h | 20 +- src/3rdparty/luajit/src/lj_asm_mips.h | 27 +- src/3rdparty/luajit/src/lj_asm_ppc.h | 27 +- src/3rdparty/luajit/src/lj_asm_x86.h | 49 +- src/3rdparty/luajit/src/lj_cparse.c | 4 +- src/3rdparty/luajit/src/lj_def.h | 11 +- src/3rdparty/luajit/src/lj_opt_fold.c | 47 +- src/3rdparty/luajit/src/lj_opt_mem.c | 15 +- src/3rdparty/luajit/src/lj_record.c | 14 +- src/3rdparty/luajit/src/lj_state.c | 7 +- src/3rdparty/luajit/src/vm_arm.dasc | 7 + src/3rdparty/luajit/src/vm_arm64.dasc | 8 + src/3rdparty/luajit/src/vm_mips.dasc | 10 +- src/3rdparty/luajit/src/vm_mips64.dasc | 12 +- src/3rdparty/luajit/src/vm_ppc.dasc | 9 + src/3rdparty/luajit/src/vm_x64.dasc | 6 + src/3rdparty/luajit/src/vm_x86.dasc | 8 +- src/3rdparty/scintilla/src/include/Lexilla.h | 14 +- .../scintilla/src/lexers/LexPython.cxx | 92 +- src/3rdparty/scintilla/src/src/CellBuffer.cxx | 27 + src/3rdparty/scintilla/src/src/CellBuffer.h | 1 + src/3rdparty/scintilla/src/src/Document.cxx | 80 +- src/3rdparty/scintilla/src/src/Document.h | 9 +- src/3rdparty/scintilla/src/src/Editor.cxx | 310 +- src/3rdparty/scintilla/src/src/Editor.h | 3 + src/3rdparty/scintilla/src/src/Indicator.h | 2 +- src/3rdparty/scintilla/src/src/RESearch.cxx | 24 +- src/3rdparty/scintilla/src/src/RESearch.h | 4 +- .../scintilla/src/src/ScintillaBase.cxx | 5 +- src/3rdparty/scintilla/src/src/Selection.h | 3 + src/3rdparty/scintilla/src/version.txt | 2 +- .../scintilla/src/win32/ScintillaWin.cxx | 2 +- src/3rdparty/sqlite3/src/sqlite3.c | 6710 +++++++++++------ src/3rdparty/sqlite3/src/sqlite3.h | 262 +- src/Makefile | 3 - src/eu_api.c | 84 +- src/eu_api.h | 27 +- src/eu_changes.c | 2 +- src/eu_code.c | 10 +- src/eu_config.c | 9 +- src/eu_document_map.c | 2 +- src/eu_edit.c | 290 +- src/eu_edit.h | 9 +- src/eu_encoding.c | 47 +- src/eu_encoding.h | 1 + src/eu_encoding_utf8.c | 389 - src/eu_encoding_utf8.h | 32 - src/eu_file.c | 615 +- src/eu_file.h | 14 +- src/eu_format.c | 8 +- src/eu_hex.c | 292 +- src/eu_locale.c | 19 +- src/eu_main.c | 32 +- src/eu_menu.c | 170 +- src/eu_menu.h | 2 +- src/eu_print.c | 2 +- src/eu_proc.c | 468 +- src/eu_proc.h | 2 +- src/eu_scintilla.c | 106 +- src/eu_script.c | 4 +- src/eu_search.c | 140 +- src/eu_search.h | 2 + src/eu_settings.c | 27 +- src/eu_share.c | 5 +- src/eu_snippet.c | 2 +- src/eu_splitter.c | 100 +- src/eu_splitter.h | 1 + src/eu_sql.h | 2 +- src/eu_statusbar.c | 280 +- src/eu_statusbar.h | 12 +- src/eu_tabpage.c | 341 +- src/eu_tabpage.h | 37 +- src/eu_theme.c | 127 +- src/eu_theme.h | 10 + src/eu_theme_dark.c | 111 +- src/eu_theme_dark.h | 10 +- src/eu_toolbar.c | 173 +- src/eu_toolbar.h | 11 +- src/eu_treebar.c | 165 +- src/eu_treebar.h | 11 +- src/eu_updatechecker.c | 10 + src/eu_updatechecker.h | 1 + src/eu_util.c | 187 +- src/eu_util.h | 37 +- src/eu_view.c | 107 +- src/eu_view.h | 11 +- src/targetver.h | 13 +- src/version_display.txt | 2 +- 103 files changed, 7945 insertions(+), 4866 deletions(-) create mode 100644 plugins/xtool/xtool.c delete mode 100644 src/eu_encoding_utf8.c delete mode 100644 src/eu_encoding_utf8.h diff --git a/conf/conf.d/eu_accel.lua b/conf/conf.d/eu_accel.lua index 17247da0..a76b21d1 100644 --- a/conf/conf.d/eu_accel.lua +++ b/conf/conf.d/eu_accel.lua @@ -21,6 +21,7 @@ function eu_accel.loadaccel() " {bit.bor(FVIRTKEY,FCONTROL), string.byte(\"W\"), IDM_FILE_CLOSE},\n", " {bit.bor(FVIRTKEY,FCONTROL,FSHIFT), VK_F4, IDM_FILE_CLOSEALL},\n", " {0, 0, IDM_FILE_CLOSEALL_EXCLUDE},\n", + " {0, 0, IDM_FILE_UNMODIFIED},\n", " {bit.bor(FVIRTKEY,FCONTROL,FSHIFT), string.byte(\"T\"), IDM_FILE_RESTORE_RECENT},\n", " {bit.bor(FVIRTKEY,FSHIFT), VK_F5, IDM_FILE_RELOAD_CURRENT},\n", " {0, 0, IDM_FILE_REMOTE_FILESERVERS},\n", @@ -122,6 +123,10 @@ function eu_accel.loadaccel() " {bit.bor(FVIRTKEY), VK_F2, IDM_SEARCH_GOTO_NEXT_BOOKMARK},\n", " {bit.bor(FVIRTKEY,FCONTROL,FSHIFT), VK_F2, IDM_SEARCH_GOTO_PREV_BOOKMARK_INALL},\n", " {bit.bor(FVIRTKEY,FSHIFT), VK_F2, IDM_SEARCH_GOTO_NEXT_BOOKMARK_INALL},\n", + " {bit.bor(FVIRTKEY,FCONTROL,FSHIFT), string.byte(\"1\"), IDM_EDIT_BOOKMARK_LINES_COPY},\n", + " {bit.bor(FVIRTKEY,FCONTROL,FSHIFT), string.byte(\"2\"), IDM_EDIT_BOOKMARK_LINES_CUT},\n", + " {bit.bor(FVIRTKEY,FCONTROL,FSHIFT), string.byte(\"3\"), IDM_EDIT_BOOKMARK_LINES_REMOVE},\n", + " {bit.bor(FVIRTKEY,FCONTROL,FSHIFT), string.byte(\"4\"), IDM_EDIT_BOOKMARK_LINES_RESERVE},\n", " {bit.bor(FVIRTKEY,FCONTROL), VK_BACK, IDM_SEARCH_NAVIGATE_PREV_THIS},\n", " {bit.bor(FVIRTKEY,FCONTROL,FSHIFT), VK_BACK, IDM_SEARCH_NAVIGATE_PREV_INALL},\n", " {bit.bor(FVIRTKEY,FCONTROL,FSHIFT), string.byte(\"A\"), IDM_SEARCH_SELECT_MATCHING_ALL},\n", @@ -146,6 +151,7 @@ function eu_accel.loadaccel() " {0, 0, IDM_TABCLOSE_NONE},\n", " {bit.bor(FVIRTKEY,FCONTROL), VK_TAB, IDM_VIEW_SWITCH_TAB},\n", " {0, 0, IDM_VIEW_SCROLLCURSOR},\n", + " {0, 0, IDM_VIEW_TABBAR_SPLIT},\n", " {bit.bor(FVIRTKEY,FCONTROL), VK_OEM_MINUS, IDM_VIEW_ZOOMOUT},\n", " {bit.bor(FVIRTKEY,FCONTROL), VK_SUBTRACT, IDM_VIEW_ZOOMOUT},\n", " {bit.bor(FVIRTKEY,FCONTROL), VK_OEM_PLUS, IDM_VIEW_ZOOMIN},\n", @@ -209,8 +215,8 @@ function eu_accel.loadaccel() end local m_len = tonumber(#my_code) if (m_len ~= nil) then - --print("m_len = " .. m_len) - if (m_len < 178) then + -- print("m_len = " .. m_len) + if (m_len < 184) then eu_core.euapi.eu_reset_accs_mask() end local m_accel = eu_core.ffi.new("ACCEL[?]", m_len, {}) diff --git a/conf/conf.d/eu_conf.lua b/conf/conf.d/eu_conf.lua index 6551c7f6..89f5cd5f 100644 --- a/conf/conf.d/eu_conf.lua +++ b/conf/conf.d/eu_conf.lua @@ -26,8 +26,9 @@ function eu_conf.fill_customize(s) ['param'] = "%CURRENT_SELSTR% %NUM_SELSTR%", ['micon'] = 44305, ['posid'] = 0, ['hbmp'] = 0} process_customized[2] = {['hide'] = false, ['name'] = "44501", ['path'] = "", ['param'] = "", ['micon'] = 0, ['posid'] = 0, ['hbmp'] = 0} - local ver = eu_core.euapi.eu_win10_or_later() - if (ver ~= 0xFFFFFFFF) then + if (eu_core.euapi.eu_under_wine()) then + process_customized[2].path = "calc" + elseif (eu_core.euapi.eu_which("win32calc.exe")) then process_customized[2].path = "%windir%/system32/win32calc.exe" else process_customized[2].path = "%windir%/system32/calc.exe" @@ -108,6 +109,7 @@ function eu_conf.loadconf() "block_fold_visiable = true\n" .. "tabs_tip_show_enable = true\n" .. "code_hint_show_enable = true\n" .. + "tab_split_show = false\n" .. "tab_close_way = 0\n" .. "tab_close_draw = 43004\n" .. "tab_new_way = 0\n" .. @@ -191,6 +193,9 @@ function eu_conf.loadconf() if (titlebar == nil) then titlebar = {["icon"] = true, ["name"] = true, ["path"] = true} end + if (tab_split_show == nil) then + tab_split_show = false; + end local m_config = eu_core.ffi.new("struct eu_config", { newfile_eols, newfile_encoding, @@ -227,6 +232,7 @@ function eu_conf.loadconf() block_fold_visiable, tabs_tip_show_enable, code_hint_show_enable, + tab_split_show, tab_close_way, tab_close_draw, tab_new_way, diff --git a/conf/conf.d/eu_core.lua b/conf/conf.d/eu_core.lua index 00c39fdf..f7491d0d 100644 --- a/conf/conf.d/eu_core.lua +++ b/conf/conf.d/eu_core.lua @@ -139,6 +139,7 @@ struct eu_config bool block_fold; bool m_tab_tip; bool m_code_hint; + bool m_tab_split; int m_close_way; int m_close_draw; @@ -470,6 +471,10 @@ void eu_reset_accs_mask(void); void eu_reset_snip_mask(void); void eu_reset_theme_mask(void); +/* 是否运行在Linux/Wine */ +bool eu_under_wine(void); +/* 文件是否在环境变量路径中 */ +bool eu_which(const char *path); /* 获取系统版本 */ const uint32_t eu_win10_or_later(void); diff --git a/conf/conf.d/eu_evaluation.lua b/conf/conf.d/eu_evaluation.lua index e59a621e..09a52a8d 100644 --- a/conf/conf.d/eu_evaluation.lua +++ b/conf/conf.d/eu_evaluation.lua @@ -6,7 +6,16 @@ local pstr = arg[1] local nlen = tonumber(arg[2]) if (pstr ~= nil and nlen ~= nil and 1 < nlen) then local ret = eu_core.euapi.eu_te_interp(eu_core.ffi.cast('const char *', pstr), nil) - if (isnan(ret)) then ret = "NaN" else ret = tostring(ret) end - if (ret == "inf") then ret = "INFINITY" end - eu_core.euapi.eu_lua_calltip(eu_core.ffi.new('char [?]', #ret + 1, ret)) + if (ret ~= nil) then + if (isnan(ret)) then ret = "NaN" else ret = tostring(ret) end + if (ret == "inf") then + ret = "INFINITY" + elseif (ret == "-inf") then + ret = "-INFINITY" + else + local x, y = math.modf(ret) + if (math.abs(x) == 0 and math.abs(y) < 1.0E-12) then ret = "0" else ret = tostring(ret) end + end + eu_core.euapi.eu_lua_calltip(ret) + end end diff --git a/conf/conf.d/eu_sci.lua b/conf/conf.d/eu_sci.lua index b48b4457..1cab7fe7 100644 --- a/conf/conf.d/eu_sci.lua +++ b/conf/conf.d/eu_sci.lua @@ -3298,6 +3298,7 @@ IDM_FILE_SAVEALL = 30419 IDM_FILE_CLOSE = 30004 IDM_FILE_CLOSEALL = 30100 IDM_FILE_CLOSEALL_EXCLUDE = 30101 +IDM_FILE_UNMODIFIED = 30028 IDM_FILE_RESTORE_RECENT = 30114 IDM_FILE_PAGESETUP = 42040 IDM_FILE_PRINT = 30005 @@ -3365,6 +3366,7 @@ IDM_EDIT_SWAP_CLIPBOARD = 30455 IDM_EDIT_CLEAR_CLIPBOARD = 30456 IDM_EDIT_COPY_INCREMENTAL = 30457 IDM_EDIT_COPY_RTF = 30458 +IDM_VIEW_TABBAR_SPLIT = 30459 IDM_EDIT_SLASH_BACKSLASH = 44100 IDM_EDIT_BACKSLASH_SLASH = 44101 -- Serach @@ -3403,6 +3405,10 @@ IDM_SEARCH_GOTO_PREV_BOOKMARK = 30017 IDM_SEARCH_GOTO_NEXT_BOOKMARK = 30018 IDM_SEARCH_GOTO_PREV_BOOKMARK_INALL = 30301 IDM_SEARCH_GOTO_NEXT_BOOKMARK_INALL = 30302 +IDM_EDIT_BOOKMARK_LINES_COPY = 30211 +IDM_EDIT_BOOKMARK_LINES_CUT = 30212 +IDM_EDIT_BOOKMARK_LINES_REMOVE = 30213 +IDM_EDIT_BOOKMARK_LINES_RESERVE = 30214 IDM_SEARCH_NAVIGATE_PREV_THIS = 30303 IDM_SEARCH_NAVIGATE_PREV_INALL = 30304 IDM_SEARCH_SELECT_MATCHING_ALL = 44700 diff --git a/conf/conf.d/eu_theme.lua b/conf/conf.d/eu_theme.lua index 9f4aa47b..4844bc91 100644 --- a/conf/conf.d/eu_theme.lua +++ b/conf/conf.d/eu_theme.lua @@ -133,8 +133,8 @@ function eu_theme.get_default(name) "xmlsection_bold = 1\n" .. "activetab_font = \"DEFAULT_GUI_FONT\"\n" .. "activetab_fontsize = 11\n" .. - "activetab_color = 0\n" .. - "activetab_bgcolor = 0x00545454\n" .. + "activetab_color = 0x00545454\n" .. + "activetab_bgcolor = 0x00C4C4C4\n" .. "activetab_bold = 0\n" .. "caret_font = \"Consolas\"\n" .. "caret_fontsize = 11\n" .. @@ -301,7 +301,7 @@ function eu_theme.get_default(name) "activetab_font = \"DEFAULT_GUI_FONT\"\n" .. "activetab_fontsize = 11\n" .. "activetab_color = 0\n" .. - "activetab_bgcolor = 0x00d77800\n" .. + "activetab_bgcolor = 0x00C4C4C4\n" .. "activetab_bold = 0\n" .. "caret_font = \"Consolas\"\n" .. "caret_fontsize = 11\n" .. @@ -470,7 +470,7 @@ function eu_theme.get_default(name) "activetab_font = \"DEFAULT_GUI_FONT\"\n" .. "activetab_fontsize = 11\n" .. "activetab_color = 0\n" .. - "activetab_bgcolor = 0x00d77800\n" .. + "activetab_bgcolor = 0x00C4C4C4\n" .. "activetab_bold = 0\n" .. "caret_font = \"Consolas\"\n" .. "caret_fontsize = 11\n" .. @@ -553,6 +553,11 @@ function eu_theme.load_default(name) dofile(file) tname = name end + -- 兼容旧代码 + if (name == "black" and activetab_bgcolor == 0x00545454 and activetab_color == 0) then + activetab_color = 0x00545454 + activetab_bgcolor = 0x00C4C4C4 + end local m_file = eu_core.ffi.new('char[260]') eu_core.ffi.C._fullpath(m_file, file, 260) local m_theme = eu_core.ffi.new("struct eu_theme", {m_file, tname, diff --git a/locales/src/en-us.rc b/locales/src/en-us.rc index 0bffe472..afa60a5e 100644 --- a/locales/src/en-us.rc +++ b/locales/src/en-us.rc @@ -36,6 +36,7 @@ BEGIN MENUITEM "&Close", IDM_FILE_CLOSE MENUITEM "Close All", IDM_FILE_CLOSEALL MENUITEM "Close Other Documents", IDM_FILE_CLOSEALL_EXCLUDE + MENUITEM "Close All Unchanged", IDM_FILE_UNMODIFIED MENUITEM MF_SEPARATOR MENUITEM "Restore Recent Closed File", IDM_FILE_RESTORE_RECENT MENUITEM "Reload The Current File", IDM_FILE_RELOAD_CURRENT @@ -202,7 +203,7 @@ BEGIN MENUITEM "Moves To The Next Block", IDM_SEARCH_MOVEBOTTOM_FIRSTLINE END MENUITEM MF_SEPARATOR - POPUP "&Go To ..." + POPUP "&Go To ...", IDM_EDIT_GOLINE_GROUP BEGIN MENUITEM "Jump To First Line", IDM_SEARCH_GOTOHOME MENUITEM "Jump To Last Line", IDM_SEARCH_GOTOEND @@ -225,6 +226,11 @@ BEGIN MENUITEM "Jump Next Bookmark (Current File)", IDM_SEARCH_GOTO_NEXT_BOOKMARK MENUITEM "Jump Previous Bookmark (All Open Files)", IDM_SEARCH_GOTO_PREV_BOOKMARK_INALL MENUITEM "Jump Next Bookmark (All Open Files)", IDM_SEARCH_GOTO_NEXT_BOOKMARK_INALL + MENUITEM MF_SEPARATOR + MENUITEM "Copy Bookmarked Lines", IDM_EDIT_BOOKMARK_LINES_COPY + MENUITEM "Cut Bookmarked Lines", IDM_EDIT_BOOKMARK_LINES_CUT + MENUITEM "Remove Bookmarked Lines", IDM_EDIT_BOOKMARK_LINES_REMOVE + MENUITEM "Remove Non-Bookmarked Lines", IDM_EDIT_BOOKMARK_LINES_RESERVE END POPUP "Navigation", IDM_EDIT_PLACEHOLDE14 BEGIN @@ -238,11 +244,12 @@ BEGIN MENUITEM "&Document Map", IDM_VIEW_DOCUMENT_MAP MENUITEM "&Symbolic Window", IDM_VIEW_SYMTREE MENUITEM MF_SEPARATOR - POPUP "P&anels" + POPUP "Panels" BEGIN MENUITEM "Full Screen Mode", IDM_VIEW_FULLSCREEN - MENUITEM "Show M&enubar", IDM_VIEW_MENUBAR - MENUITEM "Show Stat&usbar", IDM_VIEW_STATUSBAR + MENUITEM "Show Menubar", IDM_VIEW_MENUBAR + MENUITEM "Show Toolbar", IDM_VIEW_TOOLBAR + MENUITEM "Show Statusbar", IDM_VIEW_STATUSBAR END POPUP "Customize Titlebar", IDM_VIEW_TITLEBAR_GROUP BEGIN @@ -270,7 +277,7 @@ BEGIN MENUITEM MF_SEPARATOR MENUITEM "&Hex Edit View", IDM_VIEW_HEXEDIT_MODE MENUITEM MF_SEPARATOR - POPUP "H&ighlight" + POPUP "Highlight", IDM_VIEW_HIGHLIGHT_GROUP BEGIN MENUITEM "Highlight The Matching &Brace", IDM_VIEW_HIGHLIGHT_BRACE MENUITEM "Highlight The Matching &String", IDM_VIEW_HIGHLIGHT_STR @@ -278,7 +285,7 @@ BEGIN END MENUITEM "Auto Indent", IDM_EDIT_AUTO_INDENTATION MENUITEM MF_SEPARATOR - POPUP "&Display", IDM_VIEW_DISPLAY_PLACEHOLDE + POPUP "Display", IDM_VIEW_DISPLAY_PLACEHOLDE BEGIN MENUITEM "Line Numbers", IDM_VIEW_LINENUMBER_VISIABLE MENUITEM "Show Bookmark", IDM_VIEW_BOOKMARK_VISIABLE @@ -320,8 +327,12 @@ BEGIN MENUITEM "&Always Draw", IDM_TABCLOSE_ALWAYS MENUITEM "&Never Draw", IDM_TABCLOSE_NONE END - MENUITEM "Switch The Next Tab", IDM_VIEW_SWITCH_TAB - MENUITEM "Switch Tabs To Scroll To The Cursor Position", IDM_VIEW_SCROLLCURSOR + POPUP "Other Options For Tabbar" + BEGIN + MENUITEM "Switch The Next Tab", IDM_VIEW_SWITCH_TAB + MENUITEM "Scroll To Anchor When Switching Tabs", IDM_VIEW_SCROLLCURSOR + MENUITEM "Split Line On Multiline Tabs", IDM_VIEW_TABBAR_SPLIT + END MENUITEM MF_SEPARATOR POPUP "Zoom", IDM_EDIT_PLACEHOLDE_ZOOM BEGIN @@ -469,6 +480,7 @@ BEGIN BEGIN MENUITEM "&Close Tab", IDM_FILE_CLOSE MENUITEM "Close &Other Tabs", IDM_FILE_CLOSEALL_EXCLUDE + MENUITEM "Close All &Unchanged", IDM_FILE_UNMODIFIED MENUITEM "Close All Tabs", IDM_FILE_CLOSEALL MENUITEM "Close The Left Tabs", IDM_TAB_CLOSE_LEFT MENUITEM "Close The Right Tabs", IDM_TAB_CLOSE_RIGHT @@ -870,8 +882,9 @@ BEGIN MENUITEM "mac-cyrillic", IDM_OTHER_2 MENUITEM "mac-centraleurope", IDM_OTHER_3 MENUITEM "Native Codepage", IDM_OTHER_ANSI - MENUITEM "Binary code", IDM_OTHER_BIN,,0x00000003 - MENUITEM "Unknown code", IDM_UNKNOWN,,0x00000003 + MENUITEM "Binary Code", IDM_OTHER_BIN,,0x00000003 + MENUITEM "Plugins Code", IDM_OTHER_PLUGIN,,0x00000003 + MENUITEM "Unknown Code", IDM_UNKNOWN,,0x00000003 END } END diff --git a/locales/src/zh-cn.rc b/locales/src/zh-cn.rc index 214c23e7..d1fe0f35 100644 --- a/locales/src/zh-cn.rc +++ b/locales/src/zh-cn.rc @@ -36,6 +36,7 @@ BEGIN MENUITEM "关闭(&C)", IDM_FILE_CLOSE MENUITEM "关闭所有文件", IDM_FILE_CLOSEALL MENUITEM "关闭其他文件", IDM_FILE_CLOSEALL_EXCLUDE + MENUITEM "关闭未修改文件", IDM_FILE_UNMODIFIED MENUITEM MF_SEPARATOR MENUITEM "恢复最近关闭文件", IDM_FILE_RESTORE_RECENT MENUITEM "重新载入当前文件", IDM_FILE_RELOAD_CURRENT @@ -202,7 +203,7 @@ BEGIN MENUITEM "移动到下一个语句块首行", IDM_SEARCH_MOVEBOTTOM_FIRSTLINE END MENUITEM MF_SEPARATOR - POPUP "行定位(&G) ..." + POPUP "行定位(&G) ...", IDM_EDIT_GOLINE_GROUP BEGIN MENUITEM "跳到首行", IDM_SEARCH_GOTOHOME MENUITEM "跳到末行", IDM_SEARCH_GOTOEND @@ -225,6 +226,11 @@ BEGIN MENUITEM "跳到下一个书签 (当前文件)", IDM_SEARCH_GOTO_NEXT_BOOKMARK MENUITEM "跳到上一个书签 (所有打开的文件)", IDM_SEARCH_GOTO_PREV_BOOKMARK_INALL MENUITEM "跳到下一个书签 (所有打开的文件)", IDM_SEARCH_GOTO_NEXT_BOOKMARK_INALL + MENUITEM MF_SEPARATOR + MENUITEM "复制书签行", IDM_EDIT_BOOKMARK_LINES_COPY + MENUITEM "剪切书签行", IDM_EDIT_BOOKMARK_LINES_CUT + MENUITEM "删除书签行", IDM_EDIT_BOOKMARK_LINES_REMOVE + MENUITEM "删除非书签行", IDM_EDIT_BOOKMARK_LINES_RESERVE END POPUP "导航", IDM_EDIT_PLACEHOLDE14 BEGIN @@ -238,10 +244,11 @@ BEGIN MENUITEM "文档结构图(&D)", IDM_VIEW_DOCUMENT_MAP MENUITEM "符号链接窗口(&S)", IDM_VIEW_SYMTREE MENUITEM MF_SEPARATOR - POPUP "面板(&A)" + POPUP "面板" BEGIN MENUITEM "全屏模式", IDM_VIEW_FULLSCREEN MENUITEM "显示菜单栏", IDM_VIEW_MENUBAR + MENUITEM "显示工具栏", IDM_VIEW_TOOLBAR MENUITEM "显示状态栏", IDM_VIEW_STATUSBAR END POPUP "定制标题栏", IDM_VIEW_TITLEBAR_GROUP @@ -270,7 +277,7 @@ BEGIN MENUITEM MF_SEPARATOR MENUITEM "十六进制视图(&H)", IDM_VIEW_HEXEDIT_MODE MENUITEM MF_SEPARATOR - POPUP "高亮(&I)" + POPUP "高亮", IDM_VIEW_HIGHLIGHT_GROUP BEGIN MENUITEM "高亮匹配的括号(&B)", IDM_VIEW_HIGHLIGHT_BRACE MENUITEM "高亮匹配的字符串(&S)", IDM_VIEW_HIGHLIGHT_STR @@ -278,7 +285,7 @@ BEGIN END MENUITEM "自动缩进", IDM_EDIT_AUTO_INDENTATION MENUITEM MF_SEPARATOR - POPUP "显示(&D)", IDM_VIEW_DISPLAY_PLACEHOLDE + POPUP "显示", IDM_VIEW_DISPLAY_PLACEHOLDE BEGIN MENUITEM "显示行号", IDM_VIEW_LINENUMBER_VISIABLE MENUITEM "显示书签", IDM_VIEW_BOOKMARK_VISIABLE @@ -320,8 +327,12 @@ BEGIN MENUITEM "总是绘制(&A)", IDM_TABCLOSE_ALWAYS MENUITEM "从不绘制(&N)", IDM_TABCLOSE_NONE END - MENUITEM "切换到下一个标签", IDM_VIEW_SWITCH_TAB - MENUITEM "切换标签时滚动到光标所在", IDM_VIEW_SCROLLCURSOR + POPUP "标签栏其他选项" + BEGIN + MENUITEM "切换到下一个标签", IDM_VIEW_SWITCH_TAB + MENUITEM "切换标签时滚动到光标处", IDM_VIEW_SCROLLCURSOR + MENUITEM "多行标签时显示分割线", IDM_VIEW_TABBAR_SPLIT + END MENUITEM MF_SEPARATOR POPUP "缩放", IDM_EDIT_PLACEHOLDE_ZOOM BEGIN @@ -469,6 +480,7 @@ BEGIN BEGIN MENUITEM "关闭标签页(&C)", IDM_FILE_CLOSE MENUITEM "关闭其他标签页(&O)", IDM_FILE_CLOSEALL_EXCLUDE + MENUITEM "关闭未修改标签页(&U)", IDM_FILE_UNMODIFIED MENUITEM "关闭所有标签页", IDM_FILE_CLOSEALL MENUITEM "关闭左侧标签页", IDM_TAB_CLOSE_LEFT MENUITEM "关闭右侧标签页", IDM_TAB_CLOSE_RIGHT @@ -871,6 +883,7 @@ BEGIN MENUITEM "mac-centraleurope", IDM_OTHER_3 MENUITEM "本地编码", IDM_OTHER_ANSI MENUITEM "二进制编码", IDM_OTHER_BIN,,0x00000003 + MENUITEM "插件编码", IDM_OTHER_PLUGIN,,0x00000003 MENUITEM "未知编码", IDM_UNKNOWN,,0x00000003 END } diff --git a/plugins/pdfview/np_pdfviewer.c b/plugins/pdfview/np_pdfviewer.c index 4795af26..a083259e 100644 --- a/plugins/pdfview/np_pdfviewer.c +++ b/plugins/pdfview/np_pdfviewer.c @@ -1182,6 +1182,8 @@ npp_mime_type(const wchar_t *ext_name) L".djvu", L".epub", L".mobi", + L".jpg", + L".png", NULL }; if (!pdf_exe_path(path, MAX_PATH) || !pdf_exist_file(path)) diff --git a/plugins/winexy/np_winexy.c b/plugins/winexy/np_winexy.c index a8f17b83..6c6df757 100644 --- a/plugins/winexy/np_winexy.c +++ b/plugins/winexy/np_winexy.c @@ -12,6 +12,12 @@ #define NAUTILUS "/usr/bin/nautilus" #define DOLPHIN "/usr/bin/dolphin" #define XDGOPEN "/usr/bin/xdg-open" +#define GCALC1 "/usr/bin/gnome-calculator" +#define GCALC2 "/usr/bin/xcalc" +#define GCALC3 "/usr/bin/galculator" +#define KCALC1 "/usr/bin/kcalc" +#define KCALC2 "/usr/bin/kalk" +#define KCALC3 "/usr/bin/kalgebra" #define MAX_PARAMETER 256 #ifndef X_OK #define X_OK 1 /* Test for execute permission. */ @@ -23,67 +29,185 @@ extern pid_t fork(void); static int -create_terminal_process(const char *const *evp) +np_which(const char *pname, char *out, const int out_len) { - int status; + int ret = 0; + const char *path[] = {"/bin", + "/usr/bin", + "/usr/local/bin", + "/sbin", + "/usr/sbin", + "/usr/local/sbin", + "/opt/bin", + NULL + }; + if (pname && out && out_len > 0) + { + for (int i = 0; path[i]; ++i) + { + snprintf(out, out_len, "%s/%s", path[i], pname); + if (access(out, F_OK) == 0 && access(out, X_OK) == 0) + { + ret = 1; + printf("out = [%s]\n", out); + break; + } + } + if (!ret) + { + *out = 0; + } + } + return ret; +} + +static int +create_terminal_process(const char* const *evp) +{ + int status = -1; pid_t pid = fork(); if (pid == 0) - { - /* This is the child process. Execute the shell command. */ + { /* This is the child process. Execute the terminal command. */ status = execvp(evp[0], evp); _exit(EXIT_FAILURE); } - else if (pid < 0) - /* The fork failed. Report failure. */ - status = -1; + else if (pid > 0) + { + status = (int)pid; + } return status; } static int -create_shell_process(const char *param) +create_tool_process(const char* const *param) { - int status = EXIT_FAILURE; - char const *exep[8 + 1] = { NULL }; - char file_manger[MAX_PARAMETER + 1] = { 0 }; - char param_manger[MAX_PARAMETER + 1] = { 0 }; - pid_t pid = fork(); - if (pid == 0) - { - /* This is the child process. Execute the shell command. */ - if (access(NAUTILUS, F_OK) == 0 && access(NAUTILUS, X_OK) == 0) + return create_terminal_process(param); +} + +static int +create_calc_process(void) +{ + int status = -1; + pid_t pid = -1; + char const *exep[MAX_PARAMETER] = { NULL }; + char calc_manger[MAX_PARAMETER] = { 0 }; + if ((pid = fork()) == 0) + { /* This is the child process. Execute the calc command. */ + if (access(GCALC1, F_OK) == 0 && access(GCALC1, X_OK) == 0) + { + snprintf(calc_manger, MAX_PARAMETER - 1, "%s", GCALC1); + } + else if (access(GCALC2, F_OK) == 0 && access(GCALC2, X_OK) == 0) { - snprintf(file_manger, MAX_PARAMETER, "%s", NAUTILUS); - snprintf(param_manger, MAX_PARAMETER, "%s", param); + snprintf(calc_manger, MAX_PARAMETER - 1, "%s", GCALC2); } - else if (access(DOLPHIN, F_OK) == 0 && access(DOLPHIN, X_OK) == 0) + else if (access(GCALC3, F_OK) == 0 && access(GCALC3, X_OK) == 0) { - snprintf(file_manger, MAX_PARAMETER, "%s", DOLPHIN); - snprintf(param_manger, MAX_PARAMETER, "%s", param); + snprintf(calc_manger, MAX_PARAMETER - 1, "%s", GCALC3); } - else if (access(XDGOPEN, F_OK) == 0 && access(XDGOPEN, X_OK) == 0) + else if (access(KCALC1, F_OK) == 0 && access(KCALC1, X_OK) == 0) { - snprintf(file_manger, MAX_PARAMETER, "%s", XDGOPEN); - snprintf(param_manger, MAX_PARAMETER, "%s", param); - if (strrchr(param_manger, '/')) + snprintf(calc_manger, MAX_PARAMETER - 1, "%s", KCALC1); + } + else if (access(KCALC2, F_OK) == 0 && access(KCALC2, X_OK) == 0) + { + snprintf(calc_manger, MAX_PARAMETER - 1, "%s", KCALC2); + } + else if (access(KCALC3, F_OK) == 0 && access(KCALC3, X_OK) == 0) + { + snprintf(calc_manger, MAX_PARAMETER - 1, "%s", KCALC3); + } + if (calc_manger[0]) + { + exep[0] = calc_manger; + } + else + { + exep[0] = "/usr/bin/speedcrunch"; + } + _exit(execvp(exep[0], (const char* const *)exep)); + } + else if (pid > 0) + { + status = (int)pid; + } + return status; +} + +static int +create_shell_process(const char* const *param, const int hide) +{ + int i = 1; + int xdg = 0; + int status = -1; + pid_t pid = -1; + char const *exep[MAX_PARAMETER] = { NULL }; + char file_manger[MAX_PARAMETER] = { 0 }; + if ((pid = fork()) == 0) + { /* This is the child process. Execute the shell command. */ + if (!hide) + { + if (access(NAUTILUS, F_OK) == 0 && access(NAUTILUS, X_OK) == 0) + { + snprintf(file_manger, MAX_PARAMETER - 1, "%s", NAUTILUS); + } + else if (access(DOLPHIN, F_OK) == 0 && access(DOLPHIN, X_OK) == 0) + { + snprintf(file_manger, MAX_PARAMETER - 1, "%s", DOLPHIN); + } + else if (access(XDGOPEN, F_OK) == 0 && access(XDGOPEN, X_OK) == 0) { - strrchr(param_manger, '/')[0] = 0; + xdg = 1; + snprintf(file_manger, MAX_PARAMETER - 1, "%s", XDGOPEN); } } - if (file_manger[0] && param_manger[0]) + if (file_manger[0]) { + int k = 0; exep[0] = file_manger; - exep[1] = param_manger; - execvp(exep[0], exep); + for (i = 1; (i < MAX_PARAMETER - 1) && param[k]; ++i, ++k) + { + exep[i] = param[k]; + } + if (xdg) + { + for (k = i; k > 0; --k) + { + if (exep[k] && strrchr(exep[k], '/')) + { + strrchr(exep[k], '/')[0] = 0; + exep[k + 1] = NULL; + break; + } + } + } + status = execvp(exep[0], (const char* const *)exep); } else { - status = -1; + char path[260] = {0}; + const char *p = NULL; + exep[0] = param[0]; + printf("exep[0] = %s\n", exep[0]); + if (exep[0] && !(p = strchr(exep[0], '/')) && np_which(exep[0], path, 260)) + { + exep[0] = path; + } + for (i = 1; (i < MAX_PARAMETER - 1) && param[i]; ++i) + { + exep[i] = param[i]; + } + if (exep[0]) + { + status = execvp(exep[0], (const char* const *)exep); + } } _exit(status); } - else if (pid < 0) - /* The fork failed. Report failure. */ - status = -1; + else if (pid > 0) + { + status = (int)pid; + } return status; } @@ -92,7 +216,7 @@ int main(int argc, char **argv) { int ret = 0; - char const *exep[MAX_PARAMETER + 1] = { NULL }; + char const *exep[MAX_PARAMETER] = { NULL }; const char *term = TERMINAL; const char *arg_1 = "-e"; if (argc < 2) @@ -100,9 +224,17 @@ main(int argc, char **argv) printf("Parameter error\n"); ret = 1; } - else if (argc == 3 && strcmp(argv[1], "explorer.exe") == 0) + else if (argc == 2 && strcmp(argv[1], "calc") == 0) + { + ret = create_calc_process(); + } + else if (argc == 3 && strcmp(argv[1], "xtool") == 0) + { + ret = create_tool_process((const char* const *)&argv[2]); + } + else if (argc >= 3 && (strcmp(argv[1], "explorer.exe") == 0 || strcmp(argv[1], "hide.exe") == 0)) { - ret = create_shell_process(argv[2]); + ret = create_shell_process((const char * const*)&argv[2], strcmp(argv[1], "hide.exe") == 0); } else { @@ -110,15 +242,15 @@ main(int argc, char **argv) if (argc > 2 || strcmp(argv[1], "x-terminal-emulator")) { exep[1] = arg_1; - for (int k = 1, j = 2; (k < argc) && (j < MAX_PARAMETER); k++, j++) + for (int k = 1, j = 2; (k < argc) && (j < MAX_PARAMETER - 1); k++, j++) { exep[j] = argv[k]; printf("argv[%d] = %s\n", k, argv[k]); } } - ret = create_terminal_process(exep); + ret = create_terminal_process((const char* const *)exep); } printf("ret = %d\n", ret); - return ret; + return (ret > 0 ? 0 : ret); } #endif diff --git a/plugins/xtool/xtool.c b/plugins/xtool/xtool.c new file mode 100644 index 00000000..10d33598 --- /dev/null +++ b/plugins/xtool/xtool.c @@ -0,0 +1,27 @@ +#include +#include + +int +main(void) +{ + char buffer[64] = { 0 }; + FILE *pipe = popen("xdotool search --name '^Skylark - '", "r"); + if (!pipe) + { + perror("popen failed"); + return 1; + } + if (fgets(buffer, sizeof(buffer), pipe)) + { + printf("%s", buffer); + } + pclose(pipe); + if (*buffer) + { + char process[260] = { 0 }; + snprintf(process, 260, "xdotool windowactivate --sync %s", buffer); + return system(process); + } + return 0; +} + diff --git a/share/changelog b/share/changelog index 8d0f4e31..ca2f2850 100644 --- a/share/changelog +++ b/share/changelog @@ -1,3 +1,14 @@ +4.0.8 2023-12-01 adonais + * 新增: 关于书签行的编辑菜单 + * 新增: sumatrapdf解码文件到16进制的转换 + * 新增: 标签栏支持DPI, 所有主界面部件完美支持DPI + * 变更: 标签栏更紧凑的显示 + * 修复: 主题设置里插入符宽度设置问题 + * 修复: 开启文档结构图后切换到16进制模式的问题 + * 修复: 暗色主题在windows 11上的显示问题 + * 修复: Win10下, 暗色主题不随操作系统主题亮/暗切换的问题 + * 修复: 暗色主题下启动慢的问题 + 4.0.7 2023-10-24 adonais * 新增: 支持Inno与Nsis脚本高亮显示 * 新增: 通过lua脚本指定不跟随全局主题的字体样式 diff --git a/share/example_build.sh b/share/example_build.sh index 4ebc4988..79f7e7db 100644 --- a/share/example_build.sh +++ b/share/example_build.sh @@ -9,12 +9,9 @@ get_char() stty echo stty $SAVEDSTTY } - if [ -f "$0" ]; then -echo -e "$0" -echo 'Please press any key to continue...' +echo -e Runing "$0" fi - echo FULL_CURRENT_PATH = "$FULL_CURRENT_PATH" echo CURRENT_DIRECTORY = "$CURRENT_DIRECTORY" echo FILE_NAME = "$FILE_NAME" @@ -29,6 +26,7 @@ if [ "$?" == "0" ]; then chmod +x "/tmp/$NAME_PART.out" "/tmp/$NAME_PART.out" fi +echo 'Please press any key to continue...' get_char # remove execute file rm -f "/tmp/$NAME_PART.out" 2>/dev/null diff --git a/src/3rdparty/luajit/src/jit/dis_arm64.lua b/src/3rdparty/luajit/src/jit/dis_arm64.lua index a7a29494..84677666 100644 --- a/src/3rdparty/luajit/src/jit/dis_arm64.lua +++ b/src/3rdparty/luajit/src/jit/dis_arm64.lua @@ -985,8 +985,7 @@ local function disass_ins(ctx) x = x.."]" end elseif p == "P" then - local opcv, sh = rshift(op, 26), 2 - if opcv >= 0x2a then sh = 4 elseif opcv >= 0x1b then sh = 3 end + local sh = 2 + rshift(op, 31 - band(rshift(op, 26), 1)) local imm7 = lshift(arshift(lshift(op, 10), 25), sh) local rn = map_regs.x[band(rshift(op, 5), 31)] local ind = band(rshift(op, 23), 3) diff --git a/src/3rdparty/luajit/src/lj_asm_arm.h b/src/3rdparty/luajit/src/lj_asm_arm.h index ac3d1b58..348cd79f 100644 --- a/src/3rdparty/luajit/src/lj_asm_arm.h +++ b/src/3rdparty/luajit/src/lj_asm_arm.h @@ -969,24 +969,32 @@ static void asm_hrefk(ASMState *as, IRIns *ir) static void asm_uref(ASMState *as, IRIns *ir) { Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op1)) { + int guarded = (irt_t(ir->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC); + if (irref_isk(ir->op1) && !guarded) { GCfunc *fn = ir_kfunc(IR(ir->op1)); MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; emit_lsptr(as, ARMI_LDR, dest, v); } else { - Reg uv = ra_scratch(as, RSET_GPR); - Reg func = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->o == IR_UREFC) { - asm_guardcc(as, CC_NE); + if (guarded) { + asm_guardcc(as, ir->o == IR_UREFC ? CC_NE : CC_EQ); emit_n(as, ARMI_CMP|ARMI_K12|1, RID_TMP); - emit_opk(as, ARMI_ADD, dest, uv, + } + if (ir->o == IR_UREFC) + emit_opk(as, ARMI_ADD, dest, dest, (int32_t)offsetof(GCupval, tv), RSET_GPR); - emit_lso(as, ARMI_LDRB, RID_TMP, uv, (int32_t)offsetof(GCupval, closed)); + else + emit_lso(as, ARMI_LDR, dest, dest, (int32_t)offsetof(GCupval, v)); + if (guarded) + emit_lso(as, ARMI_LDRB, RID_TMP, dest, + (int32_t)offsetof(GCupval, closed)); + if (irref_isk(ir->op1)) { + GCfunc *fn = ir_kfunc(IR(ir->op1)); + int32_t k = (int32_t)gcrefu(fn->l.uvptr[(ir->op2 >> 8)]); + emit_loadi(as, dest, k); } else { - emit_lso(as, ARMI_LDR, dest, uv, (int32_t)offsetof(GCupval, v)); + emit_lso(as, ARMI_LDR, dest, ra_alloc1(as, ir->op1, RSET_GPR), + (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8)); } - emit_lso(as, ARMI_LDR, uv, func, - (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8)); } } diff --git a/src/3rdparty/luajit/src/lj_asm_arm64.h b/src/3rdparty/luajit/src/lj_asm_arm64.h index 9f165fa8..5b40f4cc 100644 --- a/src/3rdparty/luajit/src/lj_asm_arm64.h +++ b/src/3rdparty/luajit/src/lj_asm_arm64.h @@ -931,22 +931,30 @@ static void asm_hrefk(ASMState *as, IRIns *ir) static void asm_uref(ASMState *as, IRIns *ir) { Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op1)) { + int guarded = (irt_t(ir->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC); + if (irref_isk(ir->op1) && !guarded) { GCfunc *fn = ir_kfunc(IR(ir->op1)); MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; emit_lsptr(as, A64I_LDRx, dest, v); } else { - if (ir->o == IR_UREFC) { - asm_guardcnb(as, A64I_CBZ, RID_TMP); + if (guarded) + asm_guardcnb(as, ir->o == IR_UREFC ? A64I_CBZ : A64I_CBNZ, RID_TMP); + if (ir->o == IR_UREFC) emit_opk(as, A64I_ADDx, dest, dest, (int32_t)offsetof(GCupval, tv), RSET_GPR); + else + emit_lso(as, A64I_LDRx, dest, dest, (int32_t)offsetof(GCupval, v)); + if (guarded) emit_lso(as, A64I_LDRB, RID_TMP, dest, (int32_t)offsetof(GCupval, closed)); + if (irref_isk(ir->op1)) { + GCfunc *fn = ir_kfunc(IR(ir->op1)); + uint64_t k = gcrefu(fn->l.uvptr[(ir->op2 >> 8)]); + emit_loadu64(as, dest, k); } else { - emit_lso(as, A64I_LDRx, dest, dest, (int32_t)offsetof(GCupval, v)); + emit_lso(as, A64I_LDRx, dest, ra_alloc1(as, ir->op1, RSET_GPR), + (int32_t)offsetof(GCfuncL, uvptr) + 8*(int32_t)(ir->op2 >> 8)); } - emit_lso(as, A64I_LDRx, dest, ra_alloc1(as, ir->op1, RSET_GPR), - (int32_t)offsetof(GCfuncL, uvptr) + 8*(int32_t)(ir->op2 >> 8)); } } diff --git a/src/3rdparty/luajit/src/lj_asm_mips.h b/src/3rdparty/luajit/src/lj_asm_mips.h index b02da663..d4e40c91 100644 --- a/src/3rdparty/luajit/src/lj_asm_mips.h +++ b/src/3rdparty/luajit/src/lj_asm_mips.h @@ -1207,22 +1207,29 @@ static void asm_hrefk(ASMState *as, IRIns *ir) static void asm_uref(ASMState *as, IRIns *ir) { Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op1)) { + int guarded = (irt_t(ir->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC); + if (irref_isk(ir->op1) && !guarded) { GCfunc *fn = ir_kfunc(IR(ir->op1)); MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; emit_lsptr(as, MIPSI_AL, dest, v, RSET_GPR); } else { - Reg uv = ra_scratch(as, RSET_GPR); - Reg func = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->o == IR_UREFC) { - asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); - emit_tsi(as, MIPSI_AADDIU, dest, uv, (int32_t)offsetof(GCupval, tv)); - emit_tsi(as, MIPSI_LBU, RID_TMP, uv, (int32_t)offsetof(GCupval, closed)); + if (guarded) + asm_guard(as, ir->o == IR_UREFC ? MIPSI_BEQ : MIPSI_BNE, RID_TMP, RID_ZERO); + if (ir->o == IR_UREFC) + emit_tsi(as, MIPSI_AADDIU, dest, dest, (int32_t)offsetof(GCupval, tv)); + else + emit_tsi(as, MIPSI_AL, dest, dest, (int32_t)offsetof(GCupval, v)); + if (guarded) + emit_tsi(as, MIPSI_LBU, RID_TMP, dest, (int32_t)offsetof(GCupval, closed)); + if (irref_isk(ir->op1)) { + GCfunc *fn = ir_kfunc(IR(ir->op1)); + GCobj *o = gcref(fn->l.uvptr[(ir->op2 >> 8)]); + emit_loada(as, dest, o); } else { - emit_tsi(as, MIPSI_AL, dest, uv, (int32_t)offsetof(GCupval, v)); + emit_tsi(as, MIPSI_AL, dest, ra_alloc1(as, ir->op1, RSET_GPR), + (int32_t)offsetof(GCfuncL, uvptr) + + (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8)); } - emit_tsi(as, MIPSI_AL, uv, func, (int32_t)offsetof(GCfuncL, uvptr) + - (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8)); } } diff --git a/src/3rdparty/luajit/src/lj_asm_ppc.h b/src/3rdparty/luajit/src/lj_asm_ppc.h index 6555312d..8e9a92a4 100644 --- a/src/3rdparty/luajit/src/lj_asm_ppc.h +++ b/src/3rdparty/luajit/src/lj_asm_ppc.h @@ -840,23 +840,30 @@ static void asm_hrefk(ASMState *as, IRIns *ir) static void asm_uref(ASMState *as, IRIns *ir) { Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op1)) { + int guarded = (irt_t(ir->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC); + if (irref_isk(ir->op1) && !guarded) { GCfunc *fn = ir_kfunc(IR(ir->op1)); MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; emit_lsptr(as, PPCI_LWZ, dest, v, RSET_GPR); } else { - Reg uv = ra_scratch(as, RSET_GPR); - Reg func = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->o == IR_UREFC) { - asm_guardcc(as, CC_NE); + if (guarded) { + asm_guardcc(as, ir->o == IR_UREFC ? CC_NE : CC_EQ); emit_ai(as, PPCI_CMPWI, RID_TMP, 1); - emit_tai(as, PPCI_ADDI, dest, uv, (int32_t)offsetof(GCupval, tv)); - emit_tai(as, PPCI_LBZ, RID_TMP, uv, (int32_t)offsetof(GCupval, closed)); + } + if (ir->o == IR_UREFC) + emit_tai(as, PPCI_ADDI, dest, dest, (int32_t)offsetof(GCupval, tv)); + else + emit_tai(as, PPCI_LWZ, dest, dest, (int32_t)offsetof(GCupval, v)); + if (guarded) + emit_tai(as, PPCI_LBZ, RID_TMP, dest, (int32_t)offsetof(GCupval, closed)); + if (irref_isk(ir->op1)) { + GCfunc *fn = ir_kfunc(IR(ir->op1)); + int32_t k = (int32_t)gcrefu(fn->l.uvptr[(ir->op2 >> 8)]); + emit_loadi(as, dest, k); } else { - emit_tai(as, PPCI_LWZ, dest, uv, (int32_t)offsetof(GCupval, v)); + emit_tai(as, PPCI_LWZ, dest, ra_alloc1(as, ir->op1, RSET_GPR), + (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8)); } - emit_tai(as, PPCI_LWZ, uv, func, - (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8)); } } diff --git a/src/3rdparty/luajit/src/lj_asm_x86.h b/src/3rdparty/luajit/src/lj_asm_x86.h index c92de3d8..aee33716 100644 --- a/src/3rdparty/luajit/src/lj_asm_x86.h +++ b/src/3rdparty/luajit/src/lj_asm_x86.h @@ -109,7 +109,7 @@ static int asm_isk32(ASMState *as, IRRef ref, int32_t *k) /* Check if there's no conflicting instruction between curins and ref. ** Also avoid fusing loads if there are multiple references. */ -static int noconflict(ASMState *as, IRRef ref, IROp conflict, int noload) +static int noconflict(ASMState *as, IRRef ref, IROp conflict, int check) { IRIns *ir = as->ir; IRRef i = as->curins; @@ -118,7 +118,9 @@ static int noconflict(ASMState *as, IRRef ref, IROp conflict, int noload) while (--i > ref) { if (ir[i].o == conflict) return 0; /* Conflict found. */ - else if (!noload && (ir[i].op1 == ref || ir[i].op2 == ref)) + else if ((check & 1) && (ir[i].o == IR_NEWREF || ir[i].o == IR_CALLS)) + return 0; + else if ((check & 2) && (ir[i].op1 == ref || ir[i].op2 == ref)) return 0; } return 1; /* Ok, no conflict. */ @@ -134,7 +136,7 @@ static IRRef asm_fuseabase(ASMState *as, IRRef ref) lj_assertA(irb->op2 == IRFL_TAB_ARRAY, "expected FLOAD TAB_ARRAY"); /* We can avoid the FLOAD of t->array for colocated arrays. */ if (ira->o == IR_TNEW && ira->op1 <= LJ_MAX_COLOSIZE && - !neverfuse(as) && noconflict(as, irb->op1, IR_NEWREF, 1)) { + !neverfuse(as) && noconflict(as, irb->op1, IR_NEWREF, 0)) { as->mrm.ofs = (int32_t)sizeof(GCtab); /* Ofs to colocated array. */ return irb->op1; /* Table obj. */ } @@ -456,7 +458,7 @@ static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow) RegSet xallow = (allow & RSET_GPR) ? allow : RSET_GPR; if (ir->o == IR_SLOAD) { if (!(ir->op2 & (IRSLOAD_PARENT|IRSLOAD_CONVERT)) && - noconflict(as, ref, IR_RETF, 0) && + noconflict(as, ref, IR_RETF, 2) && !(LJ_GC64 && irt_isaddr(ir->t))) { as->mrm.base = (uint8_t)ra_alloc1(as, REF_BASE, xallow); as->mrm.ofs = 8*((int32_t)ir->op1-1-LJ_FR2) + @@ -467,12 +469,12 @@ static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow) } else if (ir->o == IR_FLOAD) { /* Generic fusion is only ok for 32 bit operand (but see asm_comp). */ if ((irt_isint(ir->t) || irt_isu32(ir->t) || irt_isaddr(ir->t)) && - noconflict(as, ref, IR_FSTORE, 0)) { + noconflict(as, ref, IR_FSTORE, 2)) { asm_fusefref(as, ir, xallow); return RID_MRM; } } else if (ir->o == IR_ALOAD || ir->o == IR_HLOAD || ir->o == IR_ULOAD) { - if (noconflict(as, ref, ir->o + IRDELTA_L2S, 0) && + if (noconflict(as, ref, ir->o + IRDELTA_L2S, 2+(ir->o != IR_ULOAD)) && !(LJ_GC64 && irt_isaddr(ir->t))) { asm_fuseahuref(as, ir->op1, xallow); return RID_MRM; @@ -482,7 +484,7 @@ static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow) ** Fusing unaligned memory operands is ok on x86 (except for SIMD types). */ if ((!irt_typerange(ir->t, IRT_I8, IRT_U16)) && - noconflict(as, ref, IR_XSTORE, 0)) { + noconflict(as, ref, IR_XSTORE, 2)) { asm_fusexref(as, ir->op1, xallow); return RID_MRM; } @@ -815,6 +817,7 @@ static void asm_tointg(ASMState *as, IRIns *ir, Reg left) emit_rr(as, XO_UCOMISD, left, tmp); emit_rr(as, XO_CVTSI2SD, tmp, dest); emit_rr(as, XO_XORPS, tmp, tmp); /* Avoid partial register stall. */ + checkmclim(as); emit_rr(as, XO_CVTTSD2SI, dest, left); /* Can't fuse since left is needed twice. */ } @@ -857,6 +860,7 @@ static void asm_conv(ASMState *as, IRIns *ir) emit_rr(as, XO_SUBSD, dest, bias); /* Subtract 2^52+2^51 bias. */ emit_rr(as, XO_XORPS, dest, bias); /* Merge bias and integer. */ emit_rma(as, XO_MOVSD, bias, k); + checkmclim(as); emit_mrm(as, XO_MOVD, dest, asm_fuseload(as, lref, RSET_GPR)); return; } else { /* Integer to FP conversion. */ @@ -1173,6 +1177,7 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) asm_guardcc(as, CC_E); else emit_sjcc(as, CC_E, l_end); + checkmclim(as); if (irt_isnum(kt)) { if (isk) { /* Assumes -0.0 is already canonicalized to +0.0. */ @@ -1232,7 +1237,6 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) #endif } emit_sfixup(as, l_loop); - checkmclim(as); #if LJ_GC64 if (!isk && irt_isaddr(kt)) { emit_rr(as, XO_OR, tmp|REX_64, key); @@ -1259,6 +1263,7 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) emit_rr(as, XO_ARITH(XOg_SUB), dest, tmp); emit_shifti(as, XOg_ROL, tmp, HASH_ROT3); emit_rr(as, XO_ARITH(XOg_XOR), dest, tmp); + checkmclim(as); emit_shifti(as, XOg_ROL, dest, HASH_ROT2); emit_rr(as, XO_ARITH(XOg_SUB), tmp, dest); emit_shifti(as, XOg_ROL, dest, HASH_ROT1); @@ -1276,7 +1281,6 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) } else { emit_rr(as, XO_MOV, tmp, key); #if LJ_GC64 - checkmclim(as); emit_gri(as, XG_ARITHi(XOg_XOR), dest, irt_toitype(kt) << 15); if ((as->flags & JIT_F_BMI2)) { emit_i8(as, 32); @@ -1373,24 +1377,31 @@ static void asm_hrefk(ASMState *as, IRIns *ir) static void asm_uref(ASMState *as, IRIns *ir) { Reg dest = ra_dest(as, ir, RSET_GPR); - if (irref_isk(ir->op1)) { + int guarded = (irt_t(ir->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC); + if (irref_isk(ir->op1) && !guarded) { GCfunc *fn = ir_kfunc(IR(ir->op1)); MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; emit_rma(as, XO_MOV, dest|REX_GC64, v); } else { Reg uv = ra_scratch(as, RSET_GPR); - Reg func = ra_alloc1(as, ir->op1, RSET_GPR); - if (ir->o == IR_UREFC) { + if (ir->o == IR_UREFC) emit_rmro(as, XO_LEA, dest|REX_GC64, uv, offsetof(GCupval, tv)); - asm_guardcc(as, CC_NE); - emit_i8(as, 1); + else + emit_rmro(as, XO_MOV, dest|REX_GC64, uv, offsetof(GCupval, v)); + if (guarded) { + asm_guardcc(as, ir->o == IR_UREFC ? CC_E : CC_NE); + emit_i8(as, 0); emit_rmro(as, XO_ARITHib, XOg_CMP, uv, offsetof(GCupval, closed)); + } + if (irref_isk(ir->op1)) { + GCfunc *fn = ir_kfunc(IR(ir->op1)); + GCobj *o = gcref(fn->l.uvptr[(ir->op2 >> 8)]); + emit_loada(as, uv, o); } else { - emit_rmro(as, XO_MOV, dest|REX_GC64, uv, offsetof(GCupval, v)); + emit_rmro(as, XO_MOV, uv|REX_GC64, ra_alloc1(as, ir->op1, RSET_GPR), + (int32_t)offsetof(GCfuncL, uvptr) + + (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8)); } - emit_rmro(as, XO_MOV, uv|REX_GC64, func, - (int32_t)offsetof(GCfuncL, uvptr) + - (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8)); } } @@ -1547,6 +1558,7 @@ static void asm_ahuvload(ASMState *as, IRIns *ir) if (irt_islightud(ir->t)) { Reg dest = asm_load_lightud64(as, ir, 1); if (ra_hasreg(dest)) { + checkmclim(as); asm_fuseahuref(as, ir->op1, RSET_GPR); if (ir->o == IR_VLOAD) as->mrm.ofs += 8 * ir->op2; emit_mrm(as, XO_MOV, dest|REX_64, RID_MRM); @@ -1594,6 +1606,7 @@ static void asm_ahuvload(ASMState *as, IRIns *ir) if (LJ_64 && irt_type(ir->t) >= IRT_NUM) { lj_assertA(irt_isinteger(ir->t) || irt_isnum(ir->t), "bad load type %d", irt_type(ir->t)); + checkmclim(as); #if LJ_GC64 emit_u32(as, LJ_TISNUM << 15); #else diff --git a/src/3rdparty/luajit/src/lj_cparse.c b/src/3rdparty/luajit/src/lj_cparse.c index 6c3bb2f9..9774f3a5 100644 --- a/src/3rdparty/luajit/src/lj_cparse.c +++ b/src/3rdparty/luajit/src/lj_cparse.c @@ -1766,9 +1766,11 @@ static void cp_pragma(CPState *cp, BCLine pragmaline) cp_check(cp, '('); if (cp->tok == CTOK_IDENT) { if (cp_str_is(cp->str, "push")) { - if (cp->curpack < CPARSE_MAX_PACKSTACK) { + if (cp->curpack < CPARSE_MAX_PACKSTACK-1) { cp->packstack[cp->curpack+1] = cp->packstack[cp->curpack]; cp->curpack++; + } else { + cp_errmsg(cp, cp->tok, LJ_ERR_XLEVELS); } } else if (cp_str_is(cp->str, "pop")) { if (cp->curpack > 0) cp->curpack--; diff --git a/src/3rdparty/luajit/src/lj_def.h b/src/3rdparty/luajit/src/lj_def.h index 0d6c346b..2a1d7b56 100644 --- a/src/3rdparty/luajit/src/lj_def.h +++ b/src/3rdparty/luajit/src/lj_def.h @@ -259,12 +259,8 @@ static LJ_AINLINE uint32_t lj_fls(uint32_t x) #else unsigned char _BitScanForward(unsigned long *, unsigned long); unsigned char _BitScanReverse(unsigned long *, unsigned long); -unsigned char _BitScanForward64(unsigned long *, uint64_t); -unsigned char _BitScanReverse64(unsigned long *, uint64_t); #pragma intrinsic(_BitScanForward) #pragma intrinsic(_BitScanReverse) -#pragma intrinsic(_BitScanForward64) -#pragma intrinsic(_BitScanReverse64) static LJ_AINLINE uint32_t lj_ffs(uint32_t x) { @@ -276,6 +272,12 @@ static LJ_AINLINE uint32_t lj_fls(uint32_t x) unsigned long r; _BitScanReverse(&r, x); return (uint32_t)r; } +#if defined(_M_X64) || defined(_M_ARM64) +unsigned char _BitScanForward64(unsigned long *, uint64_t); +unsigned char _BitScanReverse64(unsigned long *, uint64_t); +#pragma intrinsic(_BitScanForward64) +#pragma intrinsic(_BitScanReverse64) + static LJ_AINLINE uint32_t lj_ffs64(uint64_t x) { unsigned long r; _BitScanForward64(&r, x); return (uint32_t)r; @@ -286,6 +288,7 @@ static LJ_AINLINE uint32_t lj_fls64(uint64_t x) unsigned long r; _BitScanReverse64(&r, x); return (uint32_t)r; } #endif +#endif unsigned long _byteswap_ulong(unsigned long); uint64_t _byteswap_uint64(uint64_t); diff --git a/src/3rdparty/luajit/src/lj_opt_fold.c b/src/3rdparty/luajit/src/lj_opt_fold.c index 743dfb07..ce78505b 100644 --- a/src/3rdparty/luajit/src/lj_opt_fold.c +++ b/src/3rdparty/luajit/src/lj_opt_fold.c @@ -2134,8 +2134,26 @@ LJFOLDX(lj_opt_fwd_uload) LJFOLD(ALEN any any) LJFOLDX(lj_opt_fwd_alen) +/* Try to merge UREFO/UREFC into referenced instruction. */ +static TRef merge_uref(jit_State *J, IRRef ref, IRIns* ir) +{ + if (ir->o == IR_UREFO && irt_isguard(ir->t)) { + /* Might be pointing to some other coroutine's stack. + ** And GC might shrink said stack, thereby repointing the upvalue. + ** GC might even collect said coroutine, thereby closing the upvalue. + */ + if (gcstep_barrier(J, ref)) + return EMITFOLD; /* So cannot merge. */ + /* Current fins wants a check, but ir doesn't have one. */ + if ((irt_t(fins->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC) && + irt_type(ir->t) == IRT_IGC) + ir->t.irt += IRT_PGC-IRT_IGC; /* So install a check. */ + } + return ref; /* Not a TRef, but the caller doesn't care. */ +} + /* Upvalue refs are really loads, but there are no corresponding stores. -** So CSE is ok for them, except for UREFO across a GC step (see below). +** So CSE is ok for them, except for guarded UREFO across a GC step. ** If the referenced function is const, its upvalue addresses are const, too. ** This can be used to improve CSE by looking for the same address, ** even if the upvalues originate from a different function. @@ -2153,9 +2171,7 @@ LJFOLDF(cse_uref) if (irref_isk(ir->op1)) { GCfunc *fn2 = ir_kfunc(IR(ir->op1)); if (gco2uv(gcref(fn2->l.uvptr[(ir->op2 >> 8)])) == uv) { - if (fins->o == IR_UREFO && gcstep_barrier(J, ref)) - break; - return ref; + return merge_uref(J, ref, ir); } } ref = ir->prev; @@ -2164,6 +2180,24 @@ LJFOLDF(cse_uref) return EMITFOLD; } +/* Custom CSE for UREFO. */ +LJFOLD(UREFO any any) +LJFOLDF(cse_urefo) +{ + if (LJ_LIKELY(J->flags & JIT_F_OPT_CSE)) { + IRRef ref = J->chain[IR_UREFO]; + IRRef lim = fins->op1; + IRRef2 op12 = (IRRef2)fins->op1 + ((IRRef2)fins->op2 << 16); + while (ref > lim) { + IRIns *ir = IR(ref); + if (ir->op12 == op12) + return merge_uref(J, ref, ir); + ref = ir->prev; + } + } + return EMITFOLD; +} + LJFOLD(HREFK any any) LJFOLDX(lj_opt_fwd_hrefk) @@ -2384,14 +2418,9 @@ LJFOLDF(fold_base) /* Write barriers are amenable to CSE, but not across any incremental ** GC steps. -** -** The same logic applies to open upvalue references, because a stack -** may be resized during a GC step (not the current stack, but maybe that -** of a coroutine). */ LJFOLD(TBAR any) LJFOLD(OBAR any any) -LJFOLD(UREFO any any) LJFOLDF(barrier_tab) { TRef tr = lj_opt_cse(J); diff --git a/src/3rdparty/luajit/src/lj_opt_mem.c b/src/3rdparty/luajit/src/lj_opt_mem.c index 351d958c..631ac9e4 100644 --- a/src/3rdparty/luajit/src/lj_opt_mem.c +++ b/src/3rdparty/luajit/src/lj_opt_mem.c @@ -464,18 +464,23 @@ TRef LJ_FASTCALL lj_opt_fwd_alen(jit_State *J) */ static AliasRet aa_uref(IRIns *refa, IRIns *refb) { - if (refa->o != refb->o) - return ALIAS_NO; /* Different UREFx type. */ if (refa->op1 == refb->op1) { /* Same function. */ if (refa->op2 == refb->op2) return ALIAS_MUST; /* Same function, same upvalue idx. */ else return ALIAS_NO; /* Same function, different upvalue idx. */ } else { /* Different functions, check disambiguation hash values. */ - if (((refa->op2 ^ refb->op2) & 0xff)) + if (((refa->op2 ^ refb->op2) & 0xff)) { return ALIAS_NO; /* Upvalues with different hash values cannot alias. */ - else - return ALIAS_MAY; /* No conclusion can be drawn for same hash value. */ + } else if (refa->o != refb->o) { + /* Different UREFx type, but need to confirm the UREFO really is open. */ + if (irt_type(refa->t) == IRT_IGC) refa->t.irt += IRT_PGC-IRT_IGC; + else if (irt_type(refb->t) == IRT_IGC) refb->t.irt += IRT_PGC-IRT_IGC; + return ALIAS_NO; + } else { + /* No conclusion can be drawn for same hash value and same UREFx type. */ + return ALIAS_MAY; + } } } diff --git a/src/3rdparty/luajit/src/lj_record.c b/src/3rdparty/luajit/src/lj_record.c index d44f7737..b7af5896 100644 --- a/src/3rdparty/luajit/src/lj_record.c +++ b/src/3rdparty/luajit/src/lj_record.c @@ -976,6 +976,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) emitir(IRTG(IR_RETF, IRT_PGC), trpt, trpc); J->retdepth++; J->needsnap = 1; + J->scev.idx = REF_NIL; lj_assertJ(J->baseslot == 1+LJ_FR2, "bad baseslot for return"); /* Shift result slots up and clear the slots of the new frame below. */ memmove(J->base + cbase, J->base-1-LJ_FR2, sizeof(TRef)*nresults); @@ -1772,12 +1773,12 @@ static TRef rec_upvalue(jit_State *J, uint32_t uv, TRef val) /* Note: this effectively limits LJ_MAX_UPVAL to 127. */ uv = (uv << 8) | (hashrot(uvp->dhash, uvp->dhash + HASH_BIAS) & 0xff); if (!uvp->closed) { - uref = tref_ref(emitir(IRTG(IR_UREFO, IRT_PGC), fn, uv)); /* In current stack? */ if (uvval(uvp) >= tvref(J->L->stack) && uvval(uvp) < tvref(J->L->maxstack)) { int32_t slot = (int32_t)(uvval(uvp) - (J->L->base - J->baseslot)); if (slot >= 0) { /* Aliases an SSA slot? */ + uref = tref_ref(emitir(IRT(IR_UREFO, IRT_PGC), fn, uv)); emitir(IRTG(IR_EQ, IRT_PGC), REF_BASE, emitir(IRT(IR_ADD, IRT_PGC), uref, @@ -1792,12 +1793,21 @@ static TRef rec_upvalue(jit_State *J, uint32_t uv, TRef val) } } } + /* IR_UREFO+IRT_IGC is not checked for open-ness at runtime. + ** Always marked as a guard, since it might get promoted to IRT_PGC later. + */ + uref = emitir(IRTG(IR_UREFO, tref_isgcv(val) ? IRT_PGC : IRT_IGC), fn, uv); + uref = tref_ref(uref); emitir(IRTG(IR_UGT, IRT_PGC), emitir(IRT(IR_SUB, IRT_PGC), uref, REF_BASE), lj_ir_kintpgc(J, (J->baseslot + J->maxslot) * 8)); } else { + /* If fn is constant, then so is the GCupval*, and the upvalue cannot + ** transition back to open, so no guard is required in this case. + */ + IRType t = (tref_isk(fn) ? 0 : IRT_GUARD) | IRT_PGC; + uref = tref_ref(emitir(IRT(IR_UREFC, t), fn, uv)); needbarrier = 1; - uref = tref_ref(emitir(IRTG(IR_UREFC, IRT_PGC), fn, uv)); } if (val == 0) { /* Upvalue load */ IRType t = itype2irt(uvval(uvp)); diff --git a/src/3rdparty/luajit/src/lj_state.c b/src/3rdparty/luajit/src/lj_state.c index 6efe189d..7e4961bd 100644 --- a/src/3rdparty/luajit/src/lj_state.c +++ b/src/3rdparty/luajit/src/lj_state.c @@ -346,8 +346,11 @@ void LJ_FASTCALL lj_state_free(global_State *g, lua_State *L) lj_assertG(L != mainthread(g), "free of main thread"); if (obj2gco(L) == gcref(g->cur_L)) setgcrefnull(g->cur_L); - lj_func_closeuv(L, tvref(L->stack)); - lj_assertG(gcref(L->openupval) == NULL, "stale open upvalues"); + if (gcref(L->openupval) != NULL) { + lj_func_closeuv(L, tvref(L->stack)); + lj_trace_abort(g); /* For aa_uref soundness. */ + lj_assertG(gcref(L->openupval) == NULL, "stale open upvalues"); + } lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue); lj_mem_freet(g, L); } diff --git a/src/3rdparty/luajit/src/vm_arm.dasc b/src/3rdparty/luajit/src/vm_arm.dasc index 0d1ea95f..fc08c658 100644 --- a/src/3rdparty/luajit/src/vm_arm.dasc +++ b/src/3rdparty/luajit/src/vm_arm.dasc @@ -1195,8 +1195,11 @@ static void build_subroutines(BuildCtx *ctx) |//-- Base library: catch errors ---------------------------------------- | |.ffunc pcall + | ldr RB, L->maxstack + | add INS, BASE, NARGS8:RC | ldrb RA, [DISPATCH, #DISPATCH_GL(hookmask)] | cmp NARGS8:RC, #8 + | cmphs RB, INS | blo ->fff_fallback | tst RA, #HOOK_ACTIVE // Remember active hook before pcall. | mov RB, BASE @@ -1207,7 +1210,11 @@ static void build_subroutines(BuildCtx *ctx) | b ->vm_call_dispatch | |.ffunc_2 xpcall + | ldr RB, L->maxstack + | add INS, BASE, NARGS8:RC | ldrb RA, [DISPATCH, #DISPATCH_GL(hookmask)] + | cmp RB, INS + | blo ->fff_fallback | checkfunc CARG4, ->fff_fallback // Traceback must be a function. | mov RB, BASE | strd CARG12, [BASE, #8] // Swap function and traceback. diff --git a/src/3rdparty/luajit/src/vm_arm64.dasc b/src/3rdparty/luajit/src/vm_arm64.dasc index 2aaa64cb..a6ce0507 100644 --- a/src/3rdparty/luajit/src/vm_arm64.dasc +++ b/src/3rdparty/luajit/src/vm_arm64.dasc @@ -1211,6 +1211,10 @@ static void build_subroutines(BuildCtx *ctx) |//-- Base library: catch errors ---------------------------------------- | |.ffunc pcall + | ldr TMP1, L->maxstack + | add TMP2, BASE, NARGS8:RC + | cmp TMP1, TMP2 + | blo ->fff_fallback | cmp NARGS8:RC, #8 | ldrb TMP0w, GL->hookmask | blo ->fff_fallback @@ -1230,6 +1234,10 @@ static void build_subroutines(BuildCtx *ctx) | b ->vm_call_dispatch | |.ffunc xpcall + | ldr TMP1, L->maxstack + | add TMP2, BASE, NARGS8:RC + | cmp TMP1, TMP2 + | blo ->fff_fallback | ldp CARG1, CARG2, [BASE] | ldrb TMP0w, GL->hookmask | subs NARGS8:TMP1, NARGS8:RC, #16 diff --git a/src/3rdparty/luajit/src/vm_mips.dasc b/src/3rdparty/luajit/src/vm_mips.dasc index f276745c..8760a1f6 100644 --- a/src/3rdparty/luajit/src/vm_mips.dasc +++ b/src/3rdparty/luajit/src/vm_mips.dasc @@ -1374,9 +1374,13 @@ static void build_subroutines(BuildCtx *ctx) |//-- Base library: catch errors ---------------------------------------- | |.ffunc pcall + | lw TMP1, L->maxstack + | addu TMP2, BASE, NARGS8:RC | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) | beqz NARGS8:RC, ->fff_fallback - | move TMP2, BASE + |. sltu AT, TMP1, TMP2 + | bnez AT, ->fff_fallback + |. move TMP2, BASE | addiu BASE, BASE, 8 | // Remember active hook before pcall. | srl TMP3, TMP3, HOOK_ACTIVE_SHIFT @@ -1386,8 +1390,12 @@ static void build_subroutines(BuildCtx *ctx) |. addiu NARGS8:RC, NARGS8:RC, -8 | |.ffunc xpcall + | lw TMP1, L->maxstack + | addu TMP2, BASE, NARGS8:RC | sltiu AT, NARGS8:RC, 16 | lw CARG4, 8+HI(BASE) + | sltu TMP1, TMP1, TMP2 + | or AT, AT, TMP1 | bnez AT, ->fff_fallback |. lw CARG3, 8+LO(BASE) | lw CARG1, LO(BASE) diff --git a/src/3rdparty/luajit/src/vm_mips64.dasc b/src/3rdparty/luajit/src/vm_mips64.dasc index ef0d901d..a8d20413 100644 --- a/src/3rdparty/luajit/src/vm_mips64.dasc +++ b/src/3rdparty/luajit/src/vm_mips64.dasc @@ -1415,8 +1415,12 @@ static void build_subroutines(BuildCtx *ctx) |//-- Base library: catch errors ---------------------------------------- | |.ffunc pcall + | ld TMP1, L->maxstack + | daddu TMP2, BASE, NARGS8:RC + | sltu AT, TMP1, TMP2 + | bnez AT, ->fff_fallback + |. lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) | daddiu NARGS8:RC, NARGS8:RC, -8 - | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH) | bltz NARGS8:RC, ->fff_fallback |. move TMP2, BASE | daddiu BASE, BASE, 16 @@ -1437,8 +1441,12 @@ static void build_subroutines(BuildCtx *ctx) |. nop | |.ffunc xpcall + | ld TMP1, L->maxstack + | daddu TMP2, BASE, NARGS8:RC + | sltu AT, TMP1, TMP2 + | bnez AT, ->fff_fallback + |. ld CARG1, 0(BASE) | daddiu NARGS8:TMP0, NARGS8:RC, -16 - | ld CARG1, 0(BASE) | ld CARG2, 8(BASE) | bltz NARGS8:TMP0, ->fff_fallback |. lbu TMP1, DISPATCH_GL(hookmask)(DISPATCH) diff --git a/src/3rdparty/luajit/src/vm_ppc.dasc b/src/3rdparty/luajit/src/vm_ppc.dasc index f2e5a08f..abcc03e5 100644 --- a/src/3rdparty/luajit/src/vm_ppc.dasc +++ b/src/3rdparty/luajit/src/vm_ppc.dasc @@ -1735,8 +1735,12 @@ static void build_subroutines(BuildCtx *ctx) |//-- Base library: catch errors ---------------------------------------- | |.ffunc pcall + | lwz TMP1, L->maxstack + | add TMP2, BASE, NARGS8:RC | cmplwi NARGS8:RC, 8 | lbz TMP3, DISPATCH_GL(hookmask)(DISPATCH) + | cmplw cr1, TMP1, TMP2 + | cror 4*cr0+lt, 4*cr0+lt, 4*cr1+lt | blt ->fff_fallback | mr TMP2, BASE | la BASE, 8(BASE) @@ -1747,14 +1751,19 @@ static void build_subroutines(BuildCtx *ctx) | b ->vm_call_dispatch | |.ffunc xpcall + | lwz TMP1, L->maxstack + | add TMP2, BASE, NARGS8:RC | cmplwi NARGS8:RC, 16 | lwz CARG3, 8(BASE) + | cmplw cr1, TMP1, TMP2 |.if FPU | lfd FARG2, 8(BASE) + | cror 4*cr0+lt, 4*cr0+lt, 4*cr1+lt | lfd FARG1, 0(BASE) |.else | lwz CARG1, 0(BASE) | lwz CARG2, 4(BASE) + | cror 4*cr0+lt, 4*cr0+lt, 4*cr1+lt | lwz CARG4, 12(BASE) |.endif | blt ->fff_fallback diff --git a/src/3rdparty/luajit/src/vm_x64.dasc b/src/3rdparty/luajit/src/vm_x64.dasc index 3635ba28..8c46ea59 100644 --- a/src/3rdparty/luajit/src/vm_x64.dasc +++ b/src/3rdparty/luajit/src/vm_x64.dasc @@ -1463,6 +1463,9 @@ static void build_subroutines(BuildCtx *ctx) |//-- Base library: catch errors ---------------------------------------- | |.ffunc_1 pcall + | mov L:RB, SAVE_L + | lea RA, [BASE+NARGS:RD*8] + | cmp RA, L:RB->maxstack; ja ->fff_fallback | lea RA, [BASE+16] | sub NARGS:RDd, 1 | mov PCd, 16+FRAME_PCALL @@ -1481,6 +1484,9 @@ static void build_subroutines(BuildCtx *ctx) | jmp ->vm_call_dispatch | |.ffunc_2 xpcall + | mov L:RB, SAVE_L + | lea RA, [BASE+NARGS:RD*8] + | cmp RA, L:RB->maxstack; ja ->fff_fallback | mov LFUNC:RA, [BASE+8] | checktp_nc LFUNC:RA, LJ_TFUNC, ->fff_fallback | mov LFUNC:RB, [BASE] // Swap function and traceback. diff --git a/src/3rdparty/luajit/src/vm_x86.dasc b/src/3rdparty/luajit/src/vm_x86.dasc index c44a24ff..9c5ae384 100644 --- a/src/3rdparty/luajit/src/vm_x86.dasc +++ b/src/3rdparty/luajit/src/vm_x86.dasc @@ -1369,7 +1369,7 @@ static void build_subroutines(BuildCtx *ctx) | mov LFUNC:RB, [RA-8] | add NARGS:RD, 1 | // This is fragile. L->base must not move, KBASE must always be defined. - |.if x64 + |.if X64 | cmp KBASEa, rdx // Continue with CALLT if flag set. |.else | cmp KBASE, BASE // Continue with CALLT if flag set. @@ -1793,6 +1793,9 @@ static void build_subroutines(BuildCtx *ctx) |//-- Base library: catch errors ---------------------------------------- | |.ffunc_1 pcall + | mov L:RB, SAVE_L + | lea RA, [BASE+NARGS:RD*8] + | cmp RA, L:RB->maxstack; ja ->fff_fallback | lea RA, [BASE+8] | sub NARGS:RD, 1 | mov PC, 8+FRAME_PCALL @@ -1804,6 +1807,9 @@ static void build_subroutines(BuildCtx *ctx) | jmp ->vm_call_dispatch | |.ffunc_2 xpcall + | mov L:RB, SAVE_L + | lea RA, [BASE+NARGS:RD*8] + | cmp RA, L:RB->maxstack; ja ->fff_fallback | cmp dword [BASE+12], LJ_TFUNC; jne ->fff_fallback | mov RB, [BASE+4] // Swap function and traceback. | mov [BASE+12], RB diff --git a/src/3rdparty/scintilla/src/include/Lexilla.h b/src/3rdparty/scintilla/src/include/Lexilla.h index c17ca962..69bca7cc 100644 --- a/src/3rdparty/scintilla/src/include/Lexilla.h +++ b/src/3rdparty/scintilla/src/include/Lexilla.h @@ -48,20 +48,20 @@ using Scintilla::ILexer5; typedef void ILexer5; #endif -typedef ILexer5 *(*LexerFactoryFunction)(); +typedef ILexer5 *(*LexerFactoryFunction)(void); #if defined(__cplusplus) namespace Lexilla { #endif -typedef int (LEXILLA_CALL *GetLexerCountFn)(); +typedef int (LEXILLA_CALL *GetLexerCountFn)(void); typedef void (LEXILLA_CALL *GetLexerNameFn)(unsigned int Index, char *name, int buflength); typedef LexerFactoryFunction(LEXILLA_CALL *GetLexerFactoryFn)(unsigned int Index); typedef ILexer5*(LEXILLA_CALL *CreateLexerFn)(const char *name); DEPRECATE_DEFINITION typedef const char *(LEXILLA_CALL *LexerNameFromIDFn)(int identifier); -typedef const char *(LEXILLA_CALL *GetLibraryPropertyNamesFn)(); +typedef const char *(LEXILLA_CALL *GetLibraryPropertyNamesFn)(void); typedef void(LEXILLA_CALL *SetLibraryPropertyFn)(const char *key, const char *value); -typedef const char *(LEXILLA_CALL *GetNameSpaceFn)(); +typedef const char *(LEXILLA_CALL *GetNameSpaceFn)(void); #if defined(__cplusplus) } @@ -85,13 +85,13 @@ extern "C" { #endif ILexer5 * LEXILLA_CALL CreateLexer(const char *name); -int LEXILLA_CALL GetLexerCount(); +int LEXILLA_CALL GetLexerCount(void); void LEXILLA_CALL GetLexerName(unsigned int index, char *name, int buflength); LexerFactoryFunction LEXILLA_CALL GetLexerFactory(unsigned int index); DEPRECATE_DEFINITION const char *LEXILLA_CALL LexerNameFromID(int identifier); -const char * LEXILLA_CALL GetLibraryPropertyNames(); +const char * LEXILLA_CALL GetLibraryPropertyNames(void); void LEXILLA_CALL SetLibraryProperty(const char *key, const char *value); -const char *LEXILLA_CALL GetNameSpace(); +const char *LEXILLA_CALL GetNameSpace(void); #if defined(__cplusplus) } diff --git a/src/3rdparty/scintilla/src/lexers/LexPython.cxx b/src/3rdparty/scintilla/src/lexers/LexPython.cxx index 67c04ca6..6f29a39f 100644 --- a/src/3rdparty/scintilla/src/lexers/LexPython.cxx +++ b/src/3rdparty/scintilla/src/lexers/LexPython.cxx @@ -78,16 +78,24 @@ constexpr bool IsPyStringTypeChar(int ch, literalsAllowed allowed) noexcept { ((allowed & litF) && (ch == 'f' || ch == 'F')); } +constexpr bool IsQuote(int ch) { + return AnyOf(ch, '"', '\''); +} + +constexpr bool IsRawPrefix(int ch) { + return AnyOf(ch, 'r', 'R'); +} + bool IsPyStringStart(int ch, int chNext, int chNext2, literalsAllowed allowed) noexcept { - if (ch == '\'' || ch == '"') + if (IsQuote(ch)) return true; if (IsPyStringTypeChar(ch, allowed)) { - if (chNext == '"' || chNext == '\'') + if (IsQuote(chNext)) return true; - if ((chNext == 'r' || chNext == 'R') && (chNext2 == '"' || chNext2 == '\'')) + if (IsRawPrefix(chNext) && IsQuote(chNext2)) return true; } - if ((ch == 'r' || ch == 'R') && (chNext == '"' || chNext == '\'')) + if (IsRawPrefix(ch) && IsQuote(chNext)) return true; return false; @@ -150,12 +158,12 @@ int GetPyStringState(Accessor &styler, Sci_Position i, Sci_PositionU *nextIndex, const int firstIsF = (ch == 'f' || ch == 'F'); // Advance beyond r, u, or ur prefix (or r, b, or br in Python 2.7+ and r, f, or fr in Python 3.6+), but bail if there are any unexpected chars - if (ch == 'r' || ch == 'R') { + if (IsRawPrefix(ch)) { i++; ch = styler.SafeGetCharAt(i); chNext = styler.SafeGetCharAt(i + 1); } else if (IsPyStringTypeChar(ch, allowed)) { - if (chNext == 'r' || chNext == 'R') + if (IsRawPrefix(chNext)) i += 2; else i += 1; @@ -163,7 +171,7 @@ int GetPyStringState(Accessor &styler, Sci_Position i, Sci_PositionU *nextIndex, chNext = styler.SafeGetCharAt(i + 1); } - if (ch != '"' && ch != '\'') { + if (!IsQuote(ch)) { *nextIndex = i + 1; return SCE_P_DEFAULT; } @@ -185,7 +193,7 @@ int GetPyStringState(Accessor &styler, Sci_Position i, Sci_PositionU *nextIndex, } } -inline bool IsAWordChar(int ch, bool unicodeIdentifiers) { +bool IsAWordChar(int ch, bool unicodeIdentifiers) { if (IsASCII(ch)) return (IsAlphaNumeric(ch) || ch == '.' || ch == '_'); @@ -196,7 +204,7 @@ inline bool IsAWordChar(int ch, bool unicodeIdentifiers) { return IsXidContinue(ch); } -inline bool IsAWordStart(int ch, bool unicodeIdentifiers) { +bool IsAWordStart(int ch, bool unicodeIdentifiers) { if (IsASCII(ch)) return (IsUpperOrLowerCase(ch) || ch == '_'); @@ -212,7 +220,7 @@ bool IsFirstNonWhitespace(Sci_Position pos, Accessor &styler) { const Sci_Position start_pos = styler.LineStart(line); for (Sci_Position i = start_pos; i < pos; i++) { const char ch = styler[i]; - if (!(ch == ' ' || ch == '\t')) + if (!IsASpaceOrTab(ch)) return false; } return true; @@ -221,7 +229,7 @@ bool IsFirstNonWhitespace(Sci_Position pos, Accessor &styler) { unsigned char GetNextNonWhitespaceChar(Accessor &styler, Sci_PositionU pos, Sci_PositionU maxPos, Sci_PositionU *charPosPtr = nullptr) { while (pos < maxPos) { const unsigned char ch = styler.SafeGetCharAt(pos, '\0'); - if (!(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { + if (!AnyOf(ch, ' ', '\t', '\n', '\r')) { if (charPosPtr != nullptr) { *charPosPtr = pos; } @@ -281,8 +289,9 @@ struct OptionsPython { bool unicodeIdentifiers = true; int identifierAttributes = 0; int decoratorAttributes = 0; + bool pep701StringsF = true; - literalsAllowed AllowedLiterals() const noexcept { + [[nodiscard]] literalsAllowed AllowedLiterals() const noexcept { literalsAllowed allowedLiterals = stringsU ? litU : litNone; if (stringsB) allowedLiterals = static_cast(allowedLiterals | litB); @@ -321,6 +330,9 @@ struct OptionSetPython : public OptionSet { DefineProperty("lexer.python.strings.f", &OptionsPython::stringsF, "Set to 0 to not recognise Python 3.6 f-string literals f\"var={var}\"."); + DefineProperty("lexer.python.strings.f.pep.701", &OptionsPython::pep701StringsF, + "Set to 0 to use pre-PEP 701 / Python 3.12 f-string lexing."); + DefineProperty("lexer.python.strings.over.newline", &OptionsPython::stringsOverNewline, "Set to 1 to allow strings to span newline characters."); @@ -390,8 +402,7 @@ class LexerPython : public DefaultLexer { DefaultLexer("python", SCLEX_PYTHON, lexicalClasses, ELEMENTS(lexicalClasses)), subStyles(styleSubable, 0x80, 0x40, 0) { } - ~LexerPython() override { - } + ~LexerPython() override = default; void SCI_METHOD Release() override { delete this; } @@ -492,23 +503,29 @@ Sci_Position SCI_METHOD LexerPython::WordListSet(int n, const char *wl) { } void LexerPython::ProcessLineEnd(StyleContext &sc, std::vector &fstringStateStack, SingleFStringExpState *¤tFStringExp, bool &inContinuedString) { - long deepestSingleStateIndex = -1; - unsigned long i; - - // Find the deepest single quote state because that string will end; no \ continuation in f-string - for (i = 0; i < fstringStateStack.size(); i++) { - if (IsPySingleQuoteStringState(fstringStateStack[i].state)) { - deepestSingleStateIndex = i; - break; + // Before pep 701 single quote f-string's could not continue to a 2nd+ line + // Post pep 701, they can continue both with a trailing \ and if a { field is + // not ended with a } + if (!options.pep701StringsF) { + long deepestSingleStateIndex = -1; + unsigned long i; + + // Find the deepest single quote state because that string will end; no \ continuation in f-string + for (i = 0; i < fstringStateStack.size(); i++) { + if (IsPySingleQuoteStringState(fstringStateStack[i].state)) { + deepestSingleStateIndex = i; + break; + } } - } - if (deepestSingleStateIndex != -1) { - sc.SetState(fstringStateStack[deepestSingleStateIndex].state); - while (fstringStateStack.size() > static_cast(deepestSingleStateIndex)) { - PopFromStateStack(fstringStateStack, currentFStringExp); + if (deepestSingleStateIndex != -1) { + sc.SetState(fstringStateStack[deepestSingleStateIndex].state); + while (fstringStateStack.size() > static_cast(deepestSingleStateIndex)) { + PopFromStateStack(fstringStateStack, currentFStringExp); + } } } + if (!fstringStateStack.empty()) { std::pair > val; val.first = sc.currentLine; @@ -567,7 +584,6 @@ void SCI_METHOD LexerPython::Lex(Sci_PositionU startPos, Sci_Position length, in const literalsAllowed allowedLiterals = options.AllowedLiterals(); - initStyle = initStyle & 31; if (initStyle == SCE_P_STRINGEOL) { initStyle = SCE_P_DEFAULT; } @@ -705,7 +721,7 @@ void SCI_METHOD LexerPython::Lex(Sci_PositionU startPos, Sci_Position length, in if (attrCh == '#') isComment = true; // Detect if this attribute belongs to a decorator - if (!(ch == ' ' || ch == '\t')) + if (!IsASpaceOrTab(ch)) break; } if (((isDecoratorAttribute) && (!isComment)) && (((options.decoratorAttributes == 1) && (style == SCE_P_IDENTIFIER)) || (options.decoratorAttributes == 2))){ @@ -795,10 +811,12 @@ void SCI_METHOD LexerPython::Lex(Sci_PositionU startPos, Sci_Position length, in needEOLCheck = true; } - // If in an f-string expression, check for the ending quote(s) - // and end f-string to handle syntactically incorrect cases like - // f'{' and f"""{""" - if (!fstringStateStack.empty() && (sc.ch == '\'' || sc.ch == '"')) { + // If in an f-string expression and pre pep 701 lexing is used, + // check for the ending quote(s) and end f-string to handle + // syntactically incorrect cases like f'{' and f"""{""". Post + // pep 701, a quote may appear in a { } field so cases like + // f"n = {":".join(seq)}" is valid + if (!options.pep701StringsF && !fstringStateStack.empty() && IsQuote(sc.ch)) { long matching_stack_i = -1; for (unsigned long stack_i = 0; stack_i < fstringStateStack.size() && matching_stack_i == -1; stack_i++) { const int stack_state = fstringStateStack[stack_i].state; @@ -918,7 +936,7 @@ static bool IsCommentLine(Sci_Position line, Accessor &styler) { } static bool IsQuoteLine(Sci_Position line, const Accessor &styler) { - const int style = styler.StyleAt(styler.LineStart(line)) & 31; + const int style = styler.StyleAt(styler.LineStart(line)); return IsPyTripleQuoteStringState(style); } @@ -952,9 +970,9 @@ void SCI_METHOD LexerPython::Fold(Sci_PositionU startPos, Sci_Position length, i // Set up initial loop state startPos = styler.LineStart(lineCurrent); - int prev_state = SCE_P_DEFAULT & 31; + int prev_state = SCE_P_DEFAULT; if (lineCurrent >= 1) - prev_state = styler.StyleAt(startPos - 1) & 31; + prev_state = styler.StyleAt(startPos - 1); int prevQuote = options.foldQuotes && IsPyTripleQuoteStringState(prev_state); // Process all characters to end of requested range or end of any triple quote @@ -971,7 +989,7 @@ void SCI_METHOD LexerPython::Fold(Sci_PositionU startPos, Sci_Position length, i // Information about next line is only available if not at end of document indentNext = styler.IndentAmount(lineNext, &spaceFlags, nullptr); const Sci_Position lookAtPos = (styler.LineStart(lineNext) == styler.Length()) ? styler.Length() - 1 : styler.LineStart(lineNext); - const int style = styler.StyleAt(lookAtPos) & 31; + const int style = styler.StyleAt(lookAtPos); quote = options.foldQuotes && IsPyTripleQuoteStringState(style); } const bool quote_start = (quote && !prevQuote); diff --git a/src/3rdparty/scintilla/src/src/CellBuffer.cxx b/src/3rdparty/scintilla/src/src/CellBuffer.cxx index ba11f139..4b061db4 100644 --- a/src/3rdparty/scintilla/src/src/CellBuffer.cxx +++ b/src/3rdparty/scintilla/src/src/CellBuffer.cxx @@ -848,6 +848,33 @@ Sci::Position CellBuffer::LineStart(Sci::Line line) const noexcept { return plv->LineStart(line); } +Sci::Position CellBuffer::LineEnd(Sci::Line line) const noexcept { + if (line >= Lines() - 1) { + return LineStart(line + 1); + } else { + Sci::Position position = LineStart(line + 1); + if (LineEndType::Unicode == GetLineEndTypes()) { + const unsigned char bytes[] = { + UCharAt(position - 3), + UCharAt(position - 2), + UCharAt(position - 1), + }; + if (UTF8IsSeparator(bytes)) { + return position - UTF8SeparatorLength; + } + if (UTF8IsNEL(bytes + 1)) { + return position - UTF8NELLength; + } + } + position--; // Back over CR or LF + // When line terminator is CR+LF, may need to go back one more + if ((position > LineStart(line)) && (CharAt(position - 1) == '\r')) { + position--; + } + return position; + } +} + Sci::Line CellBuffer::LineFromPosition(Sci::Position pos) const noexcept { return plv->LineFromPosition(pos); } diff --git a/src/3rdparty/scintilla/src/src/CellBuffer.h b/src/3rdparty/scintilla/src/src/CellBuffer.h index 7f0b87c4..f0aacf8e 100644 --- a/src/3rdparty/scintilla/src/src/CellBuffer.h +++ b/src/3rdparty/scintilla/src/src/CellBuffer.h @@ -186,6 +186,7 @@ class CellBuffer { Sci::Line Lines() const noexcept; void AllocateLines(Sci::Line lines); Sci::Position LineStart(Sci::Line line) const noexcept; + Sci::Position LineEnd(Sci::Line line) const noexcept; Sci::Position IndexLineStart(Sci::Line line, Scintilla::LineCharacterIndexType lineCharacterIndex) const noexcept; Sci::Line LineFromPosition(Sci::Position pos) const noexcept; Sci::Line LineFromPositionIndex(Sci::Position pos, Scintilla::LineCharacterIndexType lineCharacterIndex) const noexcept; diff --git a/src/3rdparty/scintilla/src/src/Document.cxx b/src/3rdparty/scintilla/src/src/Document.cxx index a45479e4..a3510566 100644 --- a/src/3rdparty/scintilla/src/src/Document.cxx +++ b/src/3rdparty/scintilla/src/src/Document.cxx @@ -453,35 +453,12 @@ Range Document::LineRange(Sci::Line line) const noexcept { return {cb.LineStart(line), cb.LineStart(line + 1)}; } -bool Document::IsLineStartPosition(Sci::Position position) const { - return LineStart(LineFromPosition(position)) == position; +bool Document::IsLineStartPosition(Sci::Position position) const noexcept { + return LineStartPosition(position) == position; } Sci_Position SCI_METHOD Document::LineEnd(Sci_Position line) const { - if (line >= LinesTotal() - 1) { - return LineStart(line + 1); - } else { - Sci::Position position = LineStart(line + 1); - if (LineEndType::Unicode == cb.GetLineEndTypes()) { - const unsigned char bytes[] = { - cb.UCharAt(position-3), - cb.UCharAt(position-2), - cb.UCharAt(position-1), - }; - if (UTF8IsSeparator(bytes)) { - return position - UTF8SeparatorLength; - } - if (UTF8IsNEL(bytes+1)) { - return position - UTF8NELLength; - } - } - position--; // Back over CR or LF - // When line terminator is CR+LF, may need to go back one more - if ((position > LineStart(line)) && (cb.CharAt(position - 1) == '\r')) { - position--; - } - return position; - } + return cb.LineEnd(line); } void SCI_METHOD Document::SetErrorStatus(int status) { @@ -500,16 +477,20 @@ Sci::Line Document::SciLineFromPosition(Sci::Position pos) const noexcept { return cb.LineFromPosition(pos); } -Sci::Position Document::LineEndPosition(Sci::Position position) const { - return LineEnd(LineFromPosition(position)); +Sci::Position Document::LineStartPosition(Sci::Position position) const noexcept { + return cb.LineStart(cb.LineFromPosition(position)); +} + +Sci::Position Document::LineEndPosition(Sci::Position position) const noexcept { + return cb.LineEnd(cb.LineFromPosition(position)); } -bool Document::IsLineEndPosition(Sci::Position position) const { - return LineEnd(LineFromPosition(position)) == position; +bool Document::IsLineEndPosition(Sci::Position position) const noexcept { + return LineEndPosition(position) == position; } -bool Document::IsPositionInLineEnd(Sci::Position position) const { - return position >= LineEnd(LineFromPosition(position)); +bool Document::IsPositionInLineEnd(Sci::Position position) const noexcept { + return position >= LineEndPosition(position); } Sci::Position Document::VCHomePosition(Sci::Position position) const { @@ -790,7 +771,7 @@ Sci::Position Document::MovePositionOutsideChar(Sci::Position pos, Sci::Position } else { // Anchor DBCS calculations at start of line because start of line can // not be a DBCS trail byte. - const Sci::Position posStartLine = cb.LineStart(cb.LineFromPosition(pos)); + const Sci::Position posStartLine = LineStartPosition(pos); if (pos == posStartLine) return pos; @@ -873,7 +854,7 @@ Sci::Position Document::NextPosition(Sci::Position pos, int moveDir) const noexc } else { // Anchor DBCS calculations at start of line because start of line can // not be a DBCS trail byte. - const Sci::Position posStartLine = cb.LineStart(cb.LineFromPosition(pos)); + const Sci::Position posStartLine = LineStartPosition(pos); // See http://msdn.microsoft.com/en-us/library/cc194792%28v=MSDN.10%29.aspx // http://msdn.microsoft.com/en-us/library/cc194790.aspx if ((pos - 1) <= posStartLine) { @@ -2423,8 +2404,7 @@ void Document::EnsureStyledTo(Sci::Position pos) { if ((enteredStyling == 0) && (pos > GetEndStyled())) { IncrementStyleClock(); if (pli && !pli->UseContainerLexing()) { - const Sci::Line lineEndStyled = SciLineFromPosition(GetEndStyled()); - const Sci::Position endStyledTo = LineStart(lineEndStyled); + const Sci::Position endStyledTo = LineStartPosition(GetEndStyled()); pli->Colourise(endStyledTo, pos); } else { // Ask the watchers to style, and stop as soon as one responds. @@ -3102,7 +3082,7 @@ class UTF8Iterator { #endif -std::regex_constants::match_flag_type MatchFlags(const Document *doc, Sci::Position startPos, Sci::Position endPos) { +std::regex_constants::match_flag_type MatchFlags(const Document *doc, Sci::Position startPos, Sci::Position endPos) noexcept { std::regex_constants::match_flag_type flagsMatch = std::regex_constants::match_default; if (!doc->IsLineStartPosition(startPos)) flagsMatch |= std::regex_constants::match_not_bol; @@ -3162,11 +3142,6 @@ bool MatchOnLines(const Document *doc, const Regex ®exp, const RESearchRange for (size_t co = 0; co < match.size() && co < RESearch::MAXTAG; co++) { search.bopat[co] = match[co].first.Pos(); search.eopat[co] = match[co].second.PosRoundUp(); - const Sci::Position lenMatch = search.eopat[co] - search.bopat[co]; - search.pat[co].resize(lenMatch); - for (Sci::Position iPos = 0; iPos < lenMatch; iPos++) { - search.pat[co][iPos] = doc->CharAt(iPos + search.bopat[co]); - } } } return matched; @@ -3323,19 +3298,20 @@ Sci::Position BuiltinRegex::FindText(Document *doc, Sci::Position minPos, Sci::P const char *BuiltinRegex::SubstituteByPosition(Document *doc, const char *text, Sci::Position *length) { substituted.clear(); - const DocumentIndexer di(doc, doc->Length()); - search.GrabMatches(di); for (Sci::Position j = 0; j < *length; j++) { if (text[j] == '\\') { - if (text[j + 1] >= '0' && text[j + 1] <= '9') { - const unsigned int patNum = text[j + 1] - '0'; - const Sci::Position len = search.eopat[patNum] - search.bopat[patNum]; - if (!search.pat[patNum].empty()) // Will be null if try for a match that did not occur - substituted.append(search.pat[patNum].c_str(), len); - j++; + const char chNext = text[++j]; + if (chNext >= '0' && chNext <= '9') { + const unsigned int patNum = chNext - '0'; + const Sci::Position startPos = search.bopat[patNum]; + const Sci::Position len = search.eopat[patNum] - startPos; + if (len > 0) { // Will be null if try for a match that did not occur + const size_t size = substituted.length(); + substituted.resize(size + len); + doc->GetCharRange(substituted.data() + size, startPos, len); + } } else { - j++; - switch (text[j]) { + switch (chNext) { case 'a': substituted.push_back('\a'); break; diff --git a/src/3rdparty/scintilla/src/src/Document.h b/src/3rdparty/scintilla/src/src/Document.h index 72ed532b..f7f4eeed 100644 --- a/src/3rdparty/scintilla/src/src/Document.h +++ b/src/3rdparty/scintilla/src/src/Document.h @@ -455,11 +455,12 @@ class Document : PerLine, public Scintilla::IDocument, public Scintilla::ILoader int MarkerHandleFromLine(Sci::Line line, int which) const noexcept; Sci_Position SCI_METHOD LineStart(Sci_Position line) const override; [[nodiscard]] Range LineRange(Sci::Line line) const noexcept; - bool IsLineStartPosition(Sci::Position position) const; + bool IsLineStartPosition(Sci::Position position) const noexcept; Sci_Position SCI_METHOD LineEnd(Sci_Position line) const override; - Sci::Position LineEndPosition(Sci::Position position) const; - bool IsLineEndPosition(Sci::Position position) const; - bool IsPositionInLineEnd(Sci::Position position) const; + Sci::Position LineStartPosition(Sci::Position position) const noexcept; + Sci::Position LineEndPosition(Sci::Position position) const noexcept; + bool IsLineEndPosition(Sci::Position position) const noexcept; + bool IsPositionInLineEnd(Sci::Position position) const noexcept; Sci::Position VCHomePosition(Sci::Position position) const; Sci::Position IndexLineStart(Sci::Line line, Scintilla::LineCharacterIndexType lineCharacterIndex) const noexcept; Sci::Line LineFromPositionIndex(Sci::Position pos, Scintilla::LineCharacterIndexType lineCharacterIndex) const noexcept; diff --git a/src/3rdparty/scintilla/src/src/Editor.cxx b/src/3rdparty/scintilla/src/src/Editor.cxx index f658a998..d2d5c4a2 100644 --- a/src/3rdparty/scintilla/src/src/Editor.cxx +++ b/src/3rdparty/scintilla/src/src/Editor.cxx @@ -623,15 +623,11 @@ void Editor::InvalidateWholeSelection() { at the beginning and end of the region lines. */ SelectionRange Editor::LineSelectionRange(SelectionPosition currentPos_, SelectionPosition anchor_) const { if (currentPos_ > anchor_) { - anchor_ = SelectionPosition( - pdoc->LineStart(pdoc->LineFromPosition(anchor_.Position()))); - currentPos_ = SelectionPosition( - pdoc->LineEnd(pdoc->LineFromPosition(currentPos_.Position()))); + anchor_ = SelectionPosition(pdoc->LineStartPosition(anchor_.Position())); + currentPos_ = SelectionPosition(pdoc->LineEndPosition(currentPos_.Position())); } else { - currentPos_ = SelectionPosition( - pdoc->LineStart(pdoc->LineFromPosition(currentPos_.Position()))); - anchor_ = SelectionPosition( - pdoc->LineEnd(pdoc->LineFromPosition(anchor_.Position()))); + currentPos_ = SelectionPosition(pdoc->LineStartPosition(currentPos_.Position())); + anchor_ = SelectionPosition(pdoc->LineEndPosition(anchor_.Position())); } return SelectionRange(currentPos_, anchor_); } @@ -984,7 +980,10 @@ void Editor::VerticalCentreCaret() { void Editor::MoveSelectedLines(int lineDelta) { if (sel.IsRectangular()) { - return; + // Convert to stream selection + const SelectionRange rangeRectangular = sel.Rectangular(); + sel.Clear(); + sel.SetSelection(rangeRectangular); } // if selection doesn't start at the beginning of the line, set the new start @@ -2194,8 +2193,7 @@ void Editor::InsertPasteShape(const char *text, Sci::Position len, PasteShape sh PasteRectangular(sel.Start(), text, len); } else { if (shape == PasteShape::line) { - const Sci::Position insertPos = - pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())); + const Sci::Position insertPos = pdoc->LineStartPosition(sel.MainCaret()); Sci::Position lengthInserted = pdoc->InsertString(insertPos, text, len); // add the newline if necessary if ((len > 0) && (text[len - 1] != '\n' && text[len - 1] != '\r')) { @@ -3447,6 +3445,14 @@ constexpr bool IsRectExtend(Message iMessage, bool isRectMoveExtends) noexcept { } +Sci::Position Editor::HomeWrapPosition(Sci::Position position) { + const Sci::Position viewLineStart = StartEndDisplayLine(position, true); + const Sci::Position homePos = MovePositionSoVisible(viewLineStart, -1).Position(); + if (position <= homePos) + return pdoc->LineStartPosition(position); + return homePos; +} + Sci::Position Editor::VCHomeDisplayPosition(Sci::Position position) { const Sci::Position homePos = pdoc->VCHomePosition(position); const Sci::Position viewLineStart = StartEndDisplayLine(position, true); @@ -3475,6 +3481,125 @@ Sci::Position Editor::LineEndWrapPosition(Sci::Position position) { return endPos; } +SelectionPosition Editor::PositionMove(Message iMessage, SelectionPosition spCaret) { + switch (iMessage) { + case Message::CharLeft: + case Message::CharLeftExtend: + if (spCaret.VirtualSpace()) { + spCaret.AddVirtualSpace(-1); + } else if (!FlagSet(virtualSpaceOptions, VirtualSpace::NoWrapLineStart) || pdoc->GetColumn(spCaret.Position()) > 0) { + spCaret.Add(-1); + } + return spCaret; + case Message::CharRight: + case Message::CharRightExtend: + if (FlagSet(virtualSpaceOptions, VirtualSpace::UserAccessible) && pdoc->IsLineEndPosition(spCaret.Position())) { + spCaret.AddVirtualSpace(1); + } else { + spCaret.Add(1); + } + return spCaret; + case Message::WordLeft: + case Message::WordLeftExtend: + return SelectionPosition(pdoc->NextWordStart(spCaret.Position(), -1)); + case Message::WordRight: + case Message::WordRightExtend: + return SelectionPosition(pdoc->NextWordStart(spCaret.Position(), 1)); + case Message::WordLeftEnd: + case Message::WordLeftEndExtend: + return SelectionPosition(pdoc->NextWordEnd(spCaret.Position(), -1)); + case Message::WordRightEnd: + case Message::WordRightEndExtend: + return SelectionPosition(pdoc->NextWordEnd(spCaret.Position(), 1)); + case Message::WordPartLeft: + case Message::WordPartLeftExtend: + return SelectionPosition(pdoc->WordPartLeft(spCaret.Position())); + case Message::WordPartRight: + case Message::WordPartRightExtend: + return SelectionPosition(pdoc->WordPartRight(spCaret.Position())); + case Message::Home: + case Message::HomeExtend: + return SelectionPosition(pdoc->LineStartPosition(spCaret.Position())); + case Message::HomeDisplay: + case Message::HomeDisplayExtend: + return SelectionPosition(StartEndDisplayLine(spCaret.Position(), true)); + case Message::HomeWrap: + case Message::HomeWrapExtend: + return SelectionPosition(HomeWrapPosition(spCaret.Position())); + case Message::VCHome: + case Message::VCHomeExtend: + // VCHome alternates between beginning of line and beginning of text so may move back or forwards + return SelectionPosition(pdoc->VCHomePosition(spCaret.Position())); + case Message::VCHomeDisplay: + case Message::VCHomeDisplayExtend: + return SelectionPosition(VCHomeDisplayPosition(spCaret.Position())); + case Message::VCHomeWrap: + case Message::VCHomeWrapExtend: + return SelectionPosition(VCHomeWrapPosition(spCaret.Position())); + case Message::LineEnd: + case Message::LineEndExtend: + return SelectionPosition(pdoc->LineEndPosition(spCaret.Position())); + case Message::LineEndDisplay: + case Message::LineEndDisplayExtend: + return SelectionPosition(StartEndDisplayLine(spCaret.Position(), false)); + case Message::LineEndWrap: + case Message::LineEndWrapExtend: + return SelectionPosition(LineEndWrapPosition(spCaret.Position())); + + default: + break; + } + // Above switch should be exhaustive so this will never be reached. + PLATFORM_ASSERT(false); + return spCaret; +} + +SelectionRange Editor::SelectionMove(Scintilla::Message iMessage, size_t r) { + const SelectionPosition spCaretStart = sel.Range(r).caret; + const SelectionPosition spCaretMoved = PositionMove(iMessage, spCaretStart); + + const int directionMove = (spCaretMoved < spCaretStart) ? -1 : 1; + const SelectionPosition spCaret = MovePositionSoVisible(spCaretMoved, directionMove); + + // Handle move versus extend, and special behaviour for non-empty left/right + switch (iMessage) { + case Message::CharLeft: + case Message::CharRight: + if (sel.Range(r).Empty()) { + return SelectionRange(spCaret); + } + if (iMessage == Message::CharLeft) { + return SelectionRange(sel.Range(r).Start()); + } + return SelectionRange(sel.Range(r).End()); + + case Message::WordLeft: + case Message::WordRight: + case Message::WordLeftEnd: + case Message::WordRightEnd: + case Message::WordPartLeft: + case Message::WordPartRight: + case Message::Home: + case Message::HomeDisplay: + case Message::HomeWrap: + case Message::VCHome: + case Message::VCHomeDisplay: + case Message::VCHomeWrap: + case Message::LineEnd: + case Message::LineEndDisplay: + case Message::LineEndWrap: + return SelectionRange(spCaret); + + default: + break; + } + + // All remaining cases are *Extend + const SelectionRange rangeNew = SelectionRange(spCaret, sel.Range(r).anchor); + sel.TrimOtherSelections(r, rangeNew); + return rangeNew; +} + int Editor::HorizontalMove(Message iMessage) { if (sel.selType == Selection::SelTypes::lines) { return 0; // horizontal moves with line selection have no effect @@ -3517,8 +3642,7 @@ int Editor::HorizontalMove(Message iMessage) { break; case Message::HomeRectExtend: case Message::HomeExtend: // only when sel.IsRectangular() && sel.MoveExtends() - spCaret = SelectionPosition( - pdoc->LineStart(pdoc->LineFromPosition(spCaret.Position()))); + spCaret = SelectionPosition(pdoc->LineStartPosition(spCaret.Position())); break; case Message::VCHomeRectExtend: case Message::VCHomeExtend: // only when sel.IsRectangular() && sel.MoveExtends() @@ -3541,8 +3665,7 @@ int Editor::HorizontalMove(Message iMessage) { SelectionPosition selAtLimit = (NaturalDirection(iMessage) > 0) ? sel.Limits().end : sel.Limits().start; switch (iMessage) { case Message::Home: - selAtLimit = SelectionPosition( - pdoc->LineStart(pdoc->LineFromPosition(selAtLimit.Position()))); + selAtLimit = SelectionPosition(pdoc->LineStartPosition(selAtLimit.Position())); break; case Message::VCHome: selAtLimit = SelectionPosition(pdoc->VCHomePosition(selAtLimit.Position())); @@ -3561,154 +3684,7 @@ int Editor::HorizontalMove(Message iMessage) { sel.DropAdditionalRanges(); } for (size_t r = 0; r < sel.Count(); r++) { - const SelectionPosition spCaretNow = sel.Range(r).caret; - SelectionPosition spCaret = spCaretNow; - switch (iMessage) { - case Message::CharLeft: - case Message::CharLeftExtend: - if (spCaret.VirtualSpace()) { - spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); - } else if (!FlagSet(virtualSpaceOptions, VirtualSpace::NoWrapLineStart) || pdoc->GetColumn(spCaret.Position()) > 0) { - spCaret = SelectionPosition(spCaret.Position() - 1); - } - break; - case Message::CharRight: - case Message::CharRightExtend: - if (FlagSet(virtualSpaceOptions, VirtualSpace::UserAccessible) && pdoc->IsLineEndPosition(spCaret.Position())) { - spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); - } else { - spCaret = SelectionPosition(spCaret.Position() + 1); - } - break; - case Message::WordLeft: - case Message::WordLeftExtend: - spCaret = SelectionPosition(pdoc->NextWordStart(spCaret.Position(), -1)); - break; - case Message::WordRight: - case Message::WordRightExtend: - spCaret = SelectionPosition(pdoc->NextWordStart(spCaret.Position(), 1)); - break; - case Message::WordLeftEnd: - case Message::WordLeftEndExtend: - spCaret = SelectionPosition(pdoc->NextWordEnd(spCaret.Position(), -1)); - break; - case Message::WordRightEnd: - case Message::WordRightEndExtend: - spCaret = SelectionPosition(pdoc->NextWordEnd(spCaret.Position(), 1)); - break; - case Message::WordPartLeft: - case Message::WordPartLeftExtend: - spCaret = SelectionPosition(pdoc->WordPartLeft(spCaret.Position())); - break; - case Message::WordPartRight: - case Message::WordPartRightExtend: - spCaret = SelectionPosition(pdoc->WordPartRight(spCaret.Position())); - break; - case Message::Home: - case Message::HomeExtend: - spCaret = SelectionPosition( - pdoc->LineStart(pdoc->LineFromPosition(spCaret.Position()))); - break; - case Message::HomeDisplay: - case Message::HomeDisplayExtend: - spCaret = SelectionPosition(StartEndDisplayLine(spCaret.Position(), true)); - break; - case Message::HomeWrap: - case Message::HomeWrapExtend: - spCaret = MovePositionSoVisible(StartEndDisplayLine(spCaret.Position(), true), -1); - if (spCaretNow <= spCaret) - spCaret = SelectionPosition( - pdoc->LineStart(pdoc->LineFromPosition(spCaret.Position()))); - break; - case Message::VCHome: - case Message::VCHomeExtend: - // VCHome alternates between beginning of line and beginning of text so may move back or forwards - spCaret = SelectionPosition(pdoc->VCHomePosition(spCaret.Position())); - break; - case Message::VCHomeDisplay: - case Message::VCHomeDisplayExtend: - spCaret = SelectionPosition(VCHomeDisplayPosition(spCaret.Position())); - break; - case Message::VCHomeWrap: - case Message::VCHomeWrapExtend: - spCaret = SelectionPosition(VCHomeWrapPosition(spCaret.Position())); - break; - case Message::LineEnd: - case Message::LineEndExtend: - spCaret = SelectionPosition(pdoc->LineEndPosition(spCaret.Position())); - break; - case Message::LineEndDisplay: - case Message::LineEndDisplayExtend: - spCaret = SelectionPosition(StartEndDisplayLine(spCaret.Position(), false)); - break; - case Message::LineEndWrap: - case Message::LineEndWrapExtend: - spCaret = SelectionPosition(LineEndWrapPosition(spCaret.Position())); - break; - - default: - PLATFORM_ASSERT(false); - } - - const int directionMove = (spCaret < spCaretNow) ? -1 : 1; - spCaret = MovePositionSoVisible(spCaret, directionMove); - - // Handle move versus extend, and special behaviour for non-empty left/right - switch (iMessage) { - case Message::CharLeft: - case Message::CharRight: - if (sel.Range(r).Empty()) { - sel.Range(r) = SelectionRange(spCaret); - } else { - sel.Range(r) = SelectionRange( - (iMessage == Message::CharLeft) ? sel.Range(r).Start() : sel.Range(r).End()); - } - break; - - case Message::WordLeft: - case Message::WordRight: - case Message::WordLeftEnd: - case Message::WordRightEnd: - case Message::WordPartLeft: - case Message::WordPartRight: - case Message::Home: - case Message::HomeDisplay: - case Message::HomeWrap: - case Message::VCHome: - case Message::VCHomeDisplay: - case Message::VCHomeWrap: - case Message::LineEnd: - case Message::LineEndDisplay: - case Message::LineEndWrap: - sel.Range(r) = SelectionRange(spCaret); - break; - - case Message::CharLeftExtend: - case Message::CharRightExtend: - case Message::WordLeftExtend: - case Message::WordRightExtend: - case Message::WordLeftEndExtend: - case Message::WordRightEndExtend: - case Message::WordPartLeftExtend: - case Message::WordPartRightExtend: - case Message::HomeExtend: - case Message::HomeDisplayExtend: - case Message::HomeWrapExtend: - case Message::VCHomeExtend: - case Message::VCHomeDisplayExtend: - case Message::VCHomeWrapExtend: - case Message::LineEndExtend: - case Message::LineEndDisplayExtend: - case Message::LineEndWrapExtend: { - SelectionRange rangeNew = SelectionRange(spCaret, sel.Range(r).anchor); - sel.TrimOtherSelections(r, SelectionRange(rangeNew)); - sel.Range(r) = rangeNew; - } - break; - - default: - PLATFORM_ASSERT(false); - } + sel.Range(r) = SelectionMove(iMessage, r); } } @@ -3768,13 +3744,13 @@ int Editor::DelWordOrLine(Message iMessage) { break; case Message::DelLineLeft: rangeDelete = Range( - pdoc->LineStart(pdoc->LineFromPosition(sel.Range(r).caret.Position())), + pdoc->LineStartPosition(sel.Range(r).caret.Position()), sel.Range(r).caret.Position()); break; case Message::DelLineRight: rangeDelete = Range( sel.Range(r).caret.Position(), - pdoc->LineEnd(pdoc->LineFromPosition(sel.Range(r).caret.Position()))); + pdoc->LineEndPosition(sel.Range(r).caret.Position())); break; default: break; @@ -4607,7 +4583,7 @@ void Editor::WordSelection(Sci::Position pos) { // Extend forward to the word containing the character to the left of pos. // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line. // This ensures that a series of empty lines isn't counted as a single "word". - if (pos > pdoc->LineStart(pdoc->LineFromPosition(pos))) + if (pos > pdoc->LineStartPosition(pos)) pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos - 1, -1), 1); TrimAndSetSelection(pos, wordSelectAnchorStartPos); } else { @@ -4721,7 +4697,7 @@ void Editor::ButtonDownWithModifiers(Point pt, unsigned int curTime, KeyMod modi } else { // Selecting backwards, or anchor beyond last character on line. In these cases, // we select the word containing the character to the *left* of the anchor. - if (charPos > pdoc->LineStart(pdoc->LineFromPosition(charPos))) { + if (charPos > pdoc->LineStartPosition(charPos)) { startWord = pdoc->ExtendWordSelect(charPos, -1); endWord = pdoc->ExtendWordSelect(startWord, 1); } else { diff --git a/src/3rdparty/scintilla/src/src/Editor.h b/src/3rdparty/scintilla/src/src/Editor.h index 39707a0f..3b55b2bf 100644 --- a/src/3rdparty/scintilla/src/src/Editor.h +++ b/src/3rdparty/scintilla/src/src/Editor.h @@ -491,9 +491,12 @@ class Editor : public EditModel, public DocWatcher { void ParaUpOrDown(int direction, Selection::SelTypes selt); Range RangeDisplayLine(Sci::Line lineVisible); Sci::Position StartEndDisplayLine(Sci::Position pos, bool start); + Sci::Position HomeWrapPosition(Sci::Position position); Sci::Position VCHomeDisplayPosition(Sci::Position position); Sci::Position VCHomeWrapPosition(Sci::Position position); Sci::Position LineEndWrapPosition(Sci::Position position); + SelectionPosition PositionMove(Scintilla::Message iMessage, SelectionPosition spCaretNow); + SelectionRange SelectionMove(Scintilla::Message iMessage, size_t r); int HorizontalMove(Scintilla::Message iMessage); int DelWordOrLine(Scintilla::Message iMessage); virtual int KeyCommand(Scintilla::Message iMessage); diff --git a/src/3rdparty/scintilla/src/src/Indicator.h b/src/3rdparty/scintilla/src/src/Indicator.h index 5bdccaf3..c769539a 100644 --- a/src/3rdparty/scintilla/src/src/Indicator.h +++ b/src/3rdparty/scintilla/src/src/Indicator.h @@ -13,7 +13,7 @@ namespace Scintilla::Internal { struct StyleAndColour { Scintilla::IndicatorStyle style; ColourRGBA fore; - StyleAndColour() noexcept : style(Scintilla::IndicatorStyle::Plain), fore(0, 0, 0) { + StyleAndColour() noexcept : style(Scintilla::IndicatorStyle::Plain), fore(black) { } StyleAndColour(Scintilla::IndicatorStyle style_, ColourRGBA fore_ = black) noexcept : style(style_), fore(fore_) { } diff --git a/src/3rdparty/scintilla/src/src/RESearch.cxx b/src/3rdparty/scintilla/src/src/RESearch.cxx index 98399c92..ca0f1b55 100644 --- a/src/3rdparty/scintilla/src/src/RESearch.cxx +++ b/src/3rdparty/scintilla/src/src/RESearch.cxx @@ -264,20 +264,6 @@ RESearch::RESearch(CharClassify *charClassTable) { void RESearch::Clear() { bopat.fill(NOTFOUND); eopat.fill(NOTFOUND); - for (int i = 0; i < MAXTAG; i++) { - pat[i].clear(); - } -} - -void RESearch::GrabMatches(const CharacterIndexer &ci) { - for (unsigned int i = 0; i < MAXTAG; i++) { - if ((bopat[i] != NOTFOUND) && (eopat[i] != NOTFOUND)) { - const Sci::Position len = eopat[i] - bopat[i]; - pat[i].resize(len); - for (Sci::Position j = 0; j < len; j++) - pat[i][j] = ci.CharAt(bopat[i] + j); - } - } } void RESearch::ChSet(unsigned char c) noexcept { @@ -759,7 +745,7 @@ const char *RESearch::Compile(const char *pattern, Sci::Position length, bool ca int RESearch::Execute(const CharacterIndexer &ci, Sci::Position lp, Sci::Position endp) { unsigned char c = 0; Sci::Position ep = NOTFOUND; - char *ap = nfa; + const char * const ap = nfa; bol = lp; failure = 0; @@ -772,7 +758,7 @@ int RESearch::Execute(const CharacterIndexer &ci, Sci::Position lp, Sci::Positio ep = PMatch(ci, lp, endp, ap); break; case EOL: /* just searching for end of line normal path doesn't work */ - if (*(ap+1) == END) { + if (ap[1] == END) { lp = endp; ep = lp; break; @@ -780,7 +766,7 @@ int RESearch::Execute(const CharacterIndexer &ci, Sci::Position lp, Sci::Positio return 0; } case CHR: /* ordinary char: locate it fast */ - c = *(ap+1); + c = ap[1]; while ((lp < endp) && (static_cast(ci.CharAt(lp)) != c)) lp++; if (lp >= endp) /* if EOS, fail, else fall through. */ @@ -844,7 +830,7 @@ int RESearch::Execute(const CharacterIndexer &ci, Sci::Position lp, Sci::Positio #define CHRSKIP 3 /* [CLO] CHR chr END */ #define CCLSKIP 34 /* [CLO] CCL 32 bytes END */ -Sci::Position RESearch::PMatch(const CharacterIndexer &ci, Sci::Position lp, Sci::Position endp, char *ap) { +Sci::Position RESearch::PMatch(const CharacterIndexer &ci, Sci::Position lp, Sci::Position endp, const char *ap) { int op = 0; int c = 0; int n = 0; @@ -918,7 +904,7 @@ Sci::Position RESearch::PMatch(const CharacterIndexer &ci, Sci::Position lp, Sci n = ANYSKIP; break; case CHR: - c = *(ap+1); + c = ap[1]; if (op == CLO || op == LCLO) while ((lp < endp) && (c == ci.CharAt(lp))) lp++; diff --git a/src/3rdparty/scintilla/src/src/RESearch.h b/src/3rdparty/scintilla/src/src/RESearch.h index c142441a..05bc0e09 100644 --- a/src/3rdparty/scintilla/src/src/RESearch.h +++ b/src/3rdparty/scintilla/src/src/RESearch.h @@ -22,7 +22,6 @@ class RESearch { explicit RESearch(CharClassify *charClassTable); // No dynamic allocation so default copy constructor and assignment operator are OK. void Clear(); - void GrabMatches(const CharacterIndexer &ci); const char *Compile(const char *pattern, Sci::Position length, bool caseSensitive, bool posix) noexcept; int Execute(const CharacterIndexer &ci, Sci::Position lp, Sci::Position endp); @@ -32,7 +31,6 @@ class RESearch { using MatchPositions = std::array; MatchPositions bopat; MatchPositions eopat; - std::string pat[MAXTAG]; private: @@ -47,7 +45,7 @@ class RESearch { void ChSetWithCase(unsigned char c, bool caseSensitive) noexcept; int GetBackslashExpression(const char *pattern, int &incr) noexcept; - Sci::Position PMatch(const CharacterIndexer &ci, Sci::Position lp, Sci::Position endp, char *ap); + Sci::Position PMatch(const CharacterIndexer &ci, Sci::Position lp, Sci::Position endp, const char *ap); Sci::Position bol; Sci::Position tagstk[MAXTAG]; /* subpat tag stack */ diff --git a/src/3rdparty/scintilla/src/src/ScintillaBase.cxx b/src/3rdparty/scintilla/src/src/ScintillaBase.cxx index 9d0c79c0..a629cdd3 100644 --- a/src/3rdparty/scintilla/src/src/ScintillaBase.cxx +++ b/src/3rdparty/scintilla/src/src/ScintillaBase.cxx @@ -804,10 +804,7 @@ const char *LexState::DescriptionOfStyle(int style) { void ScintillaBase::NotifyStyleToNeeded(Sci::Position endStyleNeeded) { if (!DocumentLexState()->UseContainerLexing()) { - const Sci::Line lineEndStyled = - pdoc->SciLineFromPosition(pdoc->GetEndStyled()); - const Sci::Position endStyled = - pdoc->LineStart(lineEndStyled); + const Sci::Position endStyled = pdoc->LineStartPosition(pdoc->GetEndStyled()); DocumentLexState()->Colourise(endStyled, endStyleNeeded); return; } diff --git a/src/3rdparty/scintilla/src/src/Selection.h b/src/3rdparty/scintilla/src/src/Selection.h index bc0f2208..30e1e27a 100644 --- a/src/3rdparty/scintilla/src/src/Selection.h +++ b/src/3rdparty/scintilla/src/src/Selection.h @@ -49,6 +49,9 @@ class SelectionPosition { void Add(Sci::Position increment) noexcept { position = position + increment; } + void AddVirtualSpace(Sci::Position increment) noexcept { + SetVirtualSpace(virtualSpace + increment); + } bool IsValid() const noexcept { return position >= 0; } diff --git a/src/3rdparty/scintilla/src/version.txt b/src/3rdparty/scintilla/src/version.txt index ff5f5b64..b9e5dd76 100644 --- a/src/3rdparty/scintilla/src/version.txt +++ b/src/3rdparty/scintilla/src/version.txt @@ -1 +1 @@ -537 +540 diff --git a/src/3rdparty/scintilla/src/win32/ScintillaWin.cxx b/src/3rdparty/scintilla/src/win32/ScintillaWin.cxx index 26ea0d08..5b8d66af 100644 --- a/src/3rdparty/scintilla/src/win32/ScintillaWin.cxx +++ b/src/3rdparty/scintilla/src/win32/ScintillaWin.cxx @@ -3154,7 +3154,7 @@ LRESULT ScintillaWin::ImeOnReconvert(LPARAM lParam) { } else { // Ensure docCompStart+docCompLen be not beyond lineEnd. // since docCompLen by byte might break eol. - const Sci::Position lineEnd = pdoc->LineEnd(pdoc->LineFromPosition(rBase)); + const Sci::Position lineEnd = pdoc->LineEndPosition(rBase); const Sci::Position overflow = (docCompStart + docCompLen) - lineEnd; if (overflow > 0) { pdoc->DeleteChars(docCompStart, docCompLen - overflow); diff --git a/src/3rdparty/sqlite3/src/sqlite3.c b/src/3rdparty/sqlite3/src/sqlite3.c index a1fbd604..9443127f 100644 --- a/src/3rdparty/sqlite3/src/sqlite3.c +++ b/src/3rdparty/sqlite3/src/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.43.2. By combining all the individual C code files into this +** version 3.44.2. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -18,7 +18,7 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** 310099cce5a487035fa535dd3002c59ac7f. +** ebead0e7230cd33bcec9f95d2183069565b9. */ #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 @@ -459,9 +459,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.43.2" -#define SQLITE_VERSION_NUMBER 3043002 -#define SQLITE_SOURCE_ID "2023-10-10 12:14:04 4310099cce5a487035fa535dd3002c59ac7f1d1bec68d7cf317fd3e769484790" +#define SQLITE_VERSION "3.44.2" +#define SQLITE_VERSION_NUMBER 3044002 +#define SQLITE_SOURCE_ID "2023-11-24 11:41:44 ebead0e7230cd33bcec9f95d2183069565b9e709bf745c9b5db65cc0cbf92c0f" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -2440,7 +2440,7 @@ struct sqlite3_mem_methods { ** is stored in each sorted record and the required column values loaded ** from the database as records are returned in sorted order. The default ** value for this option is to never use this optimization. Specifying a -** negative value for this option restores the default behaviour. +** negative value for this option restores the default behavior. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. ** @@ -2615,7 +2615,7 @@ struct sqlite3_mem_methods { ** database handle, SQLite checks if this will mean that there are now no ** connections at all to the database. If so, it performs a checkpoint ** operation before closing the connection. This option may be used to -** override this behaviour. The first parameter passed to this operation +** override this behavior. The first parameter passed to this operation ** is an integer - positive to disable checkpoints-on-close, or zero (the ** default) to enable them, and negative to leave the setting unchanged. ** The second parameter is a pointer to an integer @@ -4268,6 +4268,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively. +** (See how SQLite handles [invalid UTF] for exceptions to this rule.) ** ^(Memory to hold the error message string is managed internally. ** The application does not need to worry about freeing the result. ** However, the error string might be overwritten or deallocated by @@ -5638,6 +5639,7 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); */ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); + /* ** CAPI3REF: Create Or Redefine SQL Functions ** KEYWORDS: {function creation routines} @@ -5884,13 +5886,27 @@ SQLITE_API int sqlite3_create_window_function( ** ** ** [[SQLITE_SUBTYPE]]
SQLITE_SUBTYPE
-** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call +** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. -** Specifying this flag makes no difference for scalar or aggregate user -** functions. However, if it is not specified for a user-defined window -** function, then any sub-types belonging to arguments passed to the window -** function may be discarded before the window function is called (i.e. -** sqlite3_value_subtype() will always return 0). +** This flag instructs SQLite to omit some corner-case optimizations that +** might disrupt the operation of the [sqlite3_value_subtype()] function, +** causing it to return zero rather than the correct subtype(). +** SQL functions that invokes [sqlite3_value_subtype()] should have this +** property. If the SQLITE_SUBTYPE property is omitted, then the return +** value from [sqlite3_value_subtype()] might sometimes be zero even though +** a non-zero subtype was specified by the function argument expression. +** +** [[SQLITE_RESULT_SUBTYPE]]
SQLITE_RESULT_SUBTYPE
+** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call +** [sqlite3_result_subtype()] to cause a sub-type to be associated with its +** result. +** Every function that invokes [sqlite3_result_subtype()] should have this +** property. If it does not, then the call to [sqlite3_result_subtype()] +** might become a no-op if the function is used as term in an +** [expression index]. On the other hand, SQL functions that never invoke +** [sqlite3_result_subtype()] should avoid setting this property, as the +** purpose of this property is to disable certain optimizations that are +** incompatible with subtypes. **
** */ @@ -5898,6 +5914,7 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_DIRECTONLY 0x000080000 #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 +#define SQLITE_RESULT_SUBTYPE 0x001000000 /* ** CAPI3REF: Deprecated Functions @@ -6094,6 +6111,12 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. +** +** Every [application-defined SQL function] that invoke this interface +** should include the [SQLITE_SUBTYPE] property in the text +** encoding argument when the function is [sqlite3_create_function|registered]. +** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() +** might return zero instead of the upstream subtype in some corner cases. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); @@ -6192,48 +6215,56 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** METHOD: sqlite3_context ** ** These functions may be used by (non-aggregate) SQL functions to -** associate metadata with argument values. If the same value is passed to -** multiple invocations of the same SQL function during query execution, under -** some circumstances the associated metadata may be preserved. An example -** of where this might be useful is in a regular-expression matching -** function. The compiled version of the regular expression can be stored as -** metadata associated with the pattern string. +** associate auxiliary data with argument values. If the same argument +** value is passed to multiple invocations of the same SQL function during +** query execution, under some circumstances the associated auxiliary data +** might be preserved. An example of where this might be useful is in a +** regular-expression matching function. The compiled version of the regular +** expression can be stored as auxiliary data associated with the pattern string. ** Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data ** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument ** value to the application-defined function. ^N is zero for the left-most -** function argument. ^If there is no metadata +** function argument. ^If there is no auxiliary data ** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** -** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th -** argument of the application-defined function. ^Subsequent +** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the +** N-th argument of the application-defined function. ^Subsequent ** calls to sqlite3_get_auxdata(C,N) return P from the most recent -** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or -** NULL if the metadata has been discarded. +** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or +** NULL if the auxiliary data has been discarded. ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, ** SQLite will invoke the destructor function X with parameter P exactly -** once, when the metadata is discarded. -** SQLite is free to discard the metadata at any time, including:
    +** once, when the auxiliary data is discarded. +** SQLite is free to discard the auxiliary data at any time, including:
      **
    • ^(when the corresponding function parameter changes)^, or **
    • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** SQL statement)^, or **
    • ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or **
    • ^(during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.)^
    +** allocation error occurs.)^ +**
  • ^(during the original sqlite3_set_auxdata() call if the function +** is evaluated during query planning instead of during query execution, +** as sometimes happens with [SQLITE_ENABLE_STAT4].)^
** -** Note the last bullet in particular. The destructor X in +** Note the last two bullets in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the ** function implementation should not make any use of P after -** sqlite3_set_auxdata() has been called. -** -** ^(In practice, metadata is preserved between function calls for +** sqlite3_set_auxdata() has been called. Furthermore, a call to +** sqlite3_get_auxdata() that occurs immediately after a corresponding call +** to sqlite3_set_auxdata() might still return NULL if an out-of-memory +** condition occurred during the sqlite3_set_auxdata() call or if the +** function is being evaluated during query planning rather than during +** query execution. +** +** ^(In practice, auxiliary data is preserved between function calls for ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** @@ -6243,10 +6274,67 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** ** These routines must be called from the same thread in which ** the SQL function is running. +** +** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()]. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); +/* +** CAPI3REF: Database Connection Client Data +** METHOD: sqlite3 +** +** These functions are used to associate one or more named pointers +** with a [database connection]. +** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P +** to be attached to [database connection] D using name N. Subsequent +** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P +** or a NULL pointer if there were no prior calls to +** sqlite3_set_clientdata() with the same values of D and N. +** Names are compared using strcmp() and are thus case sensitive. +** +** If P and X are both non-NULL, then the destructor X is invoked with +** argument P on the first of the following occurrences: +**
    +**
  • An out-of-memory error occurs during the call to +** sqlite3_set_clientdata() which attempts to register pointer P. +**
  • A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made +** with the same D and N parameters. +**
  • The database connection closes. SQLite does not make any guarantees +** about the order in which destructors are called, only that all +** destructors will be called exactly once at some point during the +** database connection closing process. +**
+** +** SQLite does not do anything with client data other than invoke +** destructors on the client data at the appropriate time. The intended +** use for client data is to provide a mechanism for wrapper libraries +** to store additional information about an SQLite database connection. +** +** There is no limit (other than available memory) on the number of different +** client data pointers (with different names) that can be attached to a +** single database connection. However, the implementation is optimized +** for the case of having only one or two different client data names. +** Applications and wrapper libraries are discouraged from using more than +** one client data name each. +** +** There is no way to enumerate the client data pointers +** associated with a database connection. The N parameter can be thought +** of as a secret key such that only code that knows the secret key is able +** to access the associated data. +** +** Security Warning: These interfaces should not be exposed in scripting +** languages or in other circumstances where it might be possible for an +** an attacker to invoke them. Any agent that can invoke these interfaces +** can probably also take control of the process. +** +** Database connection client data is only available for SQLite +** version 3.44.0 ([dateof:3.44.0]) and later. +** +** See also: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()]. +*/ +SQLITE_API void *sqlite3_get_clientdata(sqlite3*,const char*); +SQLITE_API int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*)); /* ** CAPI3REF: Constants Defining Special Destructor Behavior @@ -6448,6 +6536,20 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); ** higher order bits are discarded. ** The number of subtype bytes preserved by SQLite might increase ** in future releases of SQLite. +** +** Every [application-defined SQL function] that invokes this interface +** should include the [SQLITE_RESULT_SUBTYPE] property in its +** text encoding argument when the SQL function is +** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE] +** property is omitted from the function that invokes sqlite3_result_subtype(), +** then in some cases the sqlite3_result_subtype() might fail to set +** the result subtype. +** +** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any +** SQL function that invokes the sqlite3_result_subtype() interface +** and that does not have the SQLITE_RESULT_SUBTYPE property will raise +** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1 +** by default. */ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); @@ -6879,7 +6981,7 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); /* -** CAPI3REF: Allowed return values from [sqlite3_txn_state()] +** CAPI3REF: Allowed return values from sqlite3_txn_state() ** KEYWORDS: {transaction state} ** ** These constants define the current transaction state of a database file. @@ -7011,7 +7113,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); ** ^Each call to the sqlite3_autovacuum_pages() interface overrides all ** previous invocations for that database connection. ^If the callback ** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, -** then the autovacuum steps callback is cancelled. The return value +** then the autovacuum steps callback is canceled. The return value ** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might ** be some other error code if something goes wrong. The current ** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other @@ -7530,6 +7632,10 @@ struct sqlite3_module { /* The methods above are in versions 1 and 2 of the sqlite_module object. ** Those below are for version 3 and greater. */ int (*xShadowName)(const char*); + /* The methods above are in versions 1 through 3 of the sqlite_module object. + ** Those below are for version 4 and greater. */ + int (*xIntegrity)(sqlite3_vtab *pVTab, const char *zSchema, + const char *zTabName, int mFlags, char **pzErr); }; /* @@ -8017,7 +8123,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); ** code is returned and the transaction rolled back. ** ** Calling this function with an argument that is not a NULL pointer or an -** open blob handle results in undefined behaviour. ^Calling this routine +** open blob handle results in undefined behavior. ^Calling this routine ** with a null pointer (such as would be returned by a failed call to ** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function ** is passed a valid open blob handle, the values returned by the @@ -8497,6 +8603,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_PRNG_SAVE 5 #define SQLITE_TESTCTRL_PRNG_RESTORE 6 #define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */ +#define SQLITE_TESTCTRL_FK_NO_ACTION 7 #define SQLITE_TESTCTRL_BITVEC_TEST 8 #define SQLITE_TESTCTRL_FAULT_INSTALL 9 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 @@ -9558,8 +9665,8 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** blocked connection already has a registered unlock-notify callback, ** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is ** called with a NULL pointer as its second argument, then any existing -** unlock-notify callback is cancelled. ^The blocked connections -** unlock-notify callback may also be cancelled by closing the blocked +** unlock-notify callback is canceled. ^The blocked connections +** unlock-notify callback may also be canceled by closing the blocked ** connection using [sqlite3_close()]. ** ** The unlock-notify callback is not reentrant. If an application invokes @@ -10862,6 +10969,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c ** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** +** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set, +** the returned buffer content will remain accessible and unchanged +** until either the next write operation on the connection or when +** the connection is closed, and applications must not modify the +** buffer. If the bit had been clear, the returned buffer will not +** be accessed by SQLite after the call. +** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** allocation error occurs. @@ -10910,6 +11024,9 @@ SQLITE_API unsigned char *sqlite3_serialize( ** SQLite will try to increase the buffer size using sqlite3_realloc64() ** if writes on the database cause it to grow larger than M bytes. ** +** Applications must not modify the buffer P or invalidate it before +** the database connection D is closed. +** ** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. @@ -10918,6 +11035,13 @@ SQLITE_API unsigned char *sqlite3_serialize( ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the ** function returns SQLITE_ERROR. ** +** The deserialized database should not be in [WAL mode]. If the database +** is in WAL mode, then any attempt to use the database file will result +** in an [SQLITE_CANTOPEN] error. The application can set the +** [file format version numbers] (bytes 18 and 19) of the input database P +** to 0x01 prior to invoking sqlite3_deserialize(D,S,P,N,M,F) to force the +** database file into rollback mode and work around this limitation. +** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. @@ -11990,6 +12114,18 @@ SQLITE_API int sqlite3changeset_concat( ); +/* +** CAPI3REF: Upgrade the Schema of a Changeset/Patchset +*/ +SQLITE_API int sqlite3changeset_upgrade( + sqlite3 *db, + const char *zDb, + int nIn, const void *pIn, /* Input changeset */ + int *pnOut, void **ppOut /* OUT: Inverse of input */ +); + + + /* ** CAPI3REF: Changegroup Handle ** @@ -12036,6 +12172,38 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; */ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); +/* +** CAPI3REF: Add a Schema to a Changegroup +** METHOD: sqlite3_changegroup_schema +** +** This method may be used to optionally enforce the rule that the changesets +** added to the changegroup handle must match the schema of database zDb +** ("main", "temp", or the name of an attached database). If +** sqlite3changegroup_add() is called to add a changeset that is not compatible +** with the configured schema, SQLITE_SCHEMA is returned and the changegroup +** object is left in an undefined state. +** +** A changeset schema is considered compatible with the database schema in +** the same way as for sqlite3changeset_apply(). Specifically, for each +** table in the changeset, there exists a database table with: +** +**
    +**
  • The name identified by the changeset, and +**
  • at least as many columns as recorded in the changeset, and +**
  • the primary key columns in the same position as recorded in +** the changeset. +**
+** +** The output of the changegroup object always has the same schema as the +** database nominated using this function. In cases where changesets passed +** to sqlite3changegroup_add() have fewer columns than the corresponding table +** in the database schema, these are filled in using the default column +** values from the database schema. This makes it possible to combined +** changesets that have different numbers of columns for a single table +** within a changegroup, provided that they are otherwise compatible. +*/ +SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb); + /* ** CAPI3REF: Add A Changeset To A Changegroup ** METHOD: sqlite3_changegroup @@ -12104,13 +12272,18 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); ** If the new changeset contains changes to a table that is already present ** in the changegroup, then the number of columns and the position of the ** primary key columns for the table must be consistent. If this is not the -** case, this function fails with SQLITE_SCHEMA. If the input changeset -** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is -** returned. Or, if an out-of-memory condition occurs during processing, this -** function returns SQLITE_NOMEM. In all cases, if an error occurs the state -** of the final contents of the changegroup is undefined. +** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup +** object has been configured with a database schema using the +** sqlite3changegroup_schema() API, then it is possible to combine changesets +** with different numbers of columns for a single table, provided that +** they are otherwise compatible. ** -** If no error occurs, SQLITE_OK is returned. +** If the input changeset appears to be corrupt and the corruption is +** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition +** occurs during processing, this function returns SQLITE_NOMEM. +** +** In all cases, if an error occurs the state of the final contents of the +** changegroup is undefined. If no error occurs, SQLITE_OK is returned. */ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); @@ -12375,10 +12548,17 @@ SQLITE_API int sqlite3changeset_apply_v2( **
  • an insert change if all fields of the conflicting row match ** the row being inserted. ** +** +**
    SQLITE_CHANGESETAPPLY_FKNOACTION
    +** If this flag it set, then all foreign key constraints in the target +** database behave as if they were declared with "ON UPDATE NO ACTION ON +** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL +** or SET DEFAULT. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 #define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 +#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008 /* ** CAPI3REF: Constants Passed To The Conflict Handler @@ -13769,6 +13949,16 @@ struct fts5_api { # endif #endif +/* +** Enable SQLITE_USE_SEH by default on MSVC builds. Only omit +** SEH support if the -DSQLITE_OMIT_SEH option is given. +*/ +#if defined(_MSC_VER) && !defined(SQLITE_OMIT_SEH) +# define SQLITE_USE_SEH 1 +#else +# undef SQLITE_USE_SEH +#endif + /* ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. ** 0 means mutexes are permanently disable and the library is never @@ -14662,16 +14852,33 @@ typedef INT16_TYPE LogEst; ** using C-preprocessor macros. If that is unsuccessful, or if ** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined ** at run-time. +** +** If you are building SQLite on some obscure platform for which the +** following ifdef magic does not work, you can always include either: +** +** -DSQLITE_BYTEORDER=1234 +** +** or +** +** -DSQLITE_BYTEORDER=4321 +** +** to cause the build to work for little-endian or big-endian processors, +** respectively. */ -#ifndef SQLITE_BYTEORDER -# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ +#ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */ +# if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ +# define SQLITE_BYTEORDER 4321 +# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ +# define SQLITE_BYTEORDER 1234 +# elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1 +# define SQLITE_BYTEORDER 4321 +# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64) -# define SQLITE_BYTEORDER 1234 -# elif defined(sparc) || defined(__ppc__) || \ - defined(__ARMEB__) || defined(__AARCH64EB__) -# define SQLITE_BYTEORDER 4321 +# define SQLITE_BYTEORDER 1234 +# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__) +# define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 # endif @@ -14995,6 +15202,7 @@ typedef struct Column Column; typedef struct Cte Cte; typedef struct CteUse CteUse; typedef struct Db Db; +typedef struct DbClientData DbClientData; typedef struct DbFixer DbFixer; typedef struct Schema Schema; typedef struct Expr Expr; @@ -16435,19 +16643,20 @@ typedef struct VdbeOpList VdbeOpList; #define OP_VCreate 171 #define OP_VDestroy 172 #define OP_VOpen 173 -#define OP_VInitIn 174 /* synopsis: r[P2]=ValueList(P1,P3) */ -#define OP_VColumn 175 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 176 -#define OP_Pagecount 177 -#define OP_MaxPgcnt 178 -#define OP_ClrSubtype 179 /* synopsis: r[P1].subtype = 0 */ -#define OP_FilterAdd 180 /* synopsis: filter(P1) += key(P3@P4) */ -#define OP_Trace 181 -#define OP_CursorHint 182 -#define OP_ReleaseReg 183 /* synopsis: release r[P1@P2] mask P3 */ -#define OP_Noop 184 -#define OP_Explain 185 -#define OP_Abortable 186 +#define OP_VCheck 174 +#define OP_VInitIn 175 /* synopsis: r[P2]=ValueList(P1,P3) */ +#define OP_VColumn 176 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 177 +#define OP_Pagecount 178 +#define OP_MaxPgcnt 179 +#define OP_ClrSubtype 180 /* synopsis: r[P1].subtype = 0 */ +#define OP_FilterAdd 181 /* synopsis: filter(P1) += key(P3@P4) */ +#define OP_Trace 182 +#define OP_CursorHint 183 +#define OP_ReleaseReg 184 /* synopsis: release r[P1@P2] mask P3 */ +#define OP_Noop 185 +#define OP_Explain 186 +#define OP_Abortable 187 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -16482,9 +16691,9 @@ typedef struct VdbeOpList VdbeOpList; /* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ /* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\ /* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50, 0x40,\ -/* 176 */ 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,\ -/* 184 */ 0x00, 0x00, 0x00,} +/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\ +/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00,\ +/* 184 */ 0x00, 0x00, 0x00, 0x00,} /* The resolve3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum @@ -17393,6 +17602,7 @@ struct sqlite3 { i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ + DbClientData *pDbData; /* sqlite3_set_clientdata() content */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MAIN ** mutex, not by sqlite3.mutex. They are used by code in notify.c. @@ -17475,6 +17685,7 @@ struct sqlite3 { /* the count using a callback. */ #define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */ #define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */ +#define SQLITE_FkNoAction HI(0x00008) /* Treat all FK as NO ACTION */ /* Flags used only if debugging */ #ifdef SQLITE_DEBUG @@ -17643,14 +17854,15 @@ struct FuncDestructor { #define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a ** single query - might change over time */ #define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */ -/* 0x8000 -- available for reuse */ +#define SQLITE_FUNC_RUNONLY 0x8000 /* Cannot be used by valueFromFunction */ #define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ #define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ #define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */ -#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */ +/* SQLITE_SUBTYPE 0x00100000 // Consumer of subtypes */ #define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */ #define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */ #define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */ +/* SQLITE_RESULT_SUBTYPE 0x01000000 // Generator of subtypes */ #define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */ /* Identifier numbers for each in-line function */ @@ -17742,9 +17954,10 @@ struct FuncDestructor { #define MFUNCTION(zName, nArg, xPtr, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } -#define JFUNCTION(zName, nArg, iArg, xFunc) \ - {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|\ - SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ +#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, iArg, xFunc) \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\ + SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\ + ((bRS)*SQLITE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ @@ -18490,6 +18703,9 @@ struct AggInfo { FuncDef *pFunc; /* The aggregate function implementation */ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ int iDistAddr; /* Address of OP_OpenEphemeral */ + int iOBTab; /* Ephemeral table to implement ORDER BY */ + u8 bOBPayload; /* iOBTab has payload columns separate from key */ + u8 bOBUnique; /* Enforce uniqueness on iOBTab keys */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ u32 selId; /* Select to which this AggInfo belongs */ @@ -18674,7 +18890,7 @@ struct Expr { #define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_Win 0x008000 /* Contains window functions */ #define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ - /* 0x020000 // Available for reuse */ +#define EP_FullSize 0x020000 /* Expr structure must remain full sized */ #define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */ #define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */ #define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ @@ -18704,6 +18920,7 @@ struct Expr { #define ExprClearProperty(E,P) (E)->flags&=~(P) #define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue) #define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse) +#define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0) /* Macros used to ensure that the correct members of unions are accessed ** in Expr. @@ -18821,6 +19038,7 @@ struct ExprList { #define ENAME_NAME 0 /* The AS clause of a result set */ #define ENAME_SPAN 1 /* Complete text of the result set expression */ #define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */ +#define ENAME_ROWID 3 /* "DB.TABLE._rowid_" for * expansion of rowid */ /* ** An instance of this structure can hold a simple list of identifiers, @@ -19429,6 +19647,7 @@ struct Parse { int *aLabel; /* Space to hold the labels */ ExprList *pConstExpr;/* Constant expressions */ IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */ + IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */ Token constraintName;/* Name of the constraint currently being parsed */ yDbMask writeMask; /* Start a write transaction on these databases */ yDbMask cookieMask; /* Bitmask of schema verified databases */ @@ -19700,6 +19919,7 @@ struct Returning { int iRetCur; /* Transient table holding RETURNING results */ int nRetCol; /* Number of in pReturnEL after expansion */ int iRetReg; /* Register array for holding a row of RETURNING */ + char zName[40]; /* Name of trigger: "sqlite_returning_%p" */ }; /* @@ -20000,6 +20220,16 @@ struct CteUse { }; +/* Client data associated with sqlite3_set_clientdata() and +** sqlite3_get_clientdata(). +*/ +struct DbClientData { + DbClientData *pNext; /* Next in a linked list */ + void *pData; /* The data */ + void (*xDestructor)(void*); /* Destructor. Might be NULL */ + char zName[1]; /* Name of this client data. MUST BE LAST */ +}; + #ifdef SQLITE_DEBUG /* ** An instance of the TreeView object is used for printing the content of @@ -20404,6 +20634,8 @@ SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*); SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*); SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int); +SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy(Parse*,Expr*,ExprList*); +SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse*,Expr*); SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*); SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); @@ -20640,6 +20872,7 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); SQLITE_PRIVATE int sqlite3IsRowid(const char*); +SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab); SQLITE_PRIVATE void sqlite3GenerateRowDelete( Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int); SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); @@ -20911,7 +21144,8 @@ SQLITE_PRIVATE int sqlite3MatchEName( const struct ExprList_item*, const char*, const char*, - const char* + const char*, + int* ); SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr*); SQLITE_PRIVATE u8 sqlite3StrIHash(const char*); @@ -20968,7 +21202,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int); SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *); SQLITE_PRIVATE char *sqlite3RCStrRef(char*); -SQLITE_PRIVATE void sqlite3RCStrUnref(char*); +SQLITE_PRIVATE void sqlite3RCStrUnref(void*); SQLITE_PRIVATE char *sqlite3RCStrNew(u64); SQLITE_PRIVATE char *sqlite3RCStrResize(char*,u64); @@ -21804,6 +22038,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS "EXPLAIN_ESTIMATED_ROWS", #endif +#ifdef SQLITE_EXTRA_AUTOEXT + "EXTRA_AUTOEXT=" CTIMEOPT_VAL(SQLITE_EXTRA_AUTOEXT), +#endif #ifdef SQLITE_EXTRA_IFNULLROW "EXTRA_IFNULLROW", #endif @@ -22085,6 +22322,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS "OMIT_SCHEMA_VERSION_PRAGMAS", #endif +#ifdef SQLITE_OMIT_SEH + "OMIT_SEH", +#endif #ifdef SQLITE_OMIT_SHARED_CACHE "OMIT_SHARED_CACHE", #endif @@ -25044,13 +25284,16 @@ static void strftimeFunc( computeJD(&x); computeYMD_HMS(&x); for(i=j=0; zFmt[i]; i++){ + char cf; if( zFmt[i]!='%' ) continue; if( j12 ) h -= 12; + if( h==0 ) h = 12; + sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h); break; } case 'W': /* Fall thru */ @@ -25072,7 +25328,7 @@ static void strftimeFunc( y.D = 1; computeJD(&y); nDay = (int)((x.iJD-y.iJD+43200000)/86400000); - if( zFmt[i]=='W' ){ + if( cf=='W' ){ int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ wd = (int)(((x.iJD+43200000)/86400000)%7); sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7); @@ -25093,6 +25349,19 @@ static void strftimeFunc( sqlite3_str_appendf(&sRes,"%02d",x.m); break; } + case 'p': /* Fall thru */ + case 'P': { + if( x.h>=12 ){ + sqlite3_str_append(&sRes, cf=='p' ? "PM" : "pm", 2); + }else{ + sqlite3_str_append(&sRes, cf=='p' ? "AM" : "am", 2); + } + break; + } + case 'R': { + sqlite3_str_appendf(&sRes, "%02d:%02d", x.h, x.m); + break; + } case 's': { if( x.useSubsec ){ sqlite3_str_appendf(&sRes,"%.3f", @@ -25107,9 +25376,15 @@ static void strftimeFunc( sqlite3_str_appendf(&sRes,"%02d",(int)x.s); break; } + case 'T': { + sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s); + break; + } + case 'u': /* Fall thru */ case 'w': { - sqlite3_str_appendchar(&sRes, 1, - (char)(((x.iJD+129600000)/86400000) % 7) + '0'); + char c = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; + if( c=='0' && cf=='u' ) c = '7'; + sqlite3_str_appendchar(&sRes, 1, c); break; } case 'Y': { @@ -28198,7 +28473,7 @@ static void checkMutexFree(sqlite3_mutex *p){ assert( SQLITE_MUTEX_FAST<2 ); assert( SQLITE_MUTEX_WARNONCONTENTION<2 ); -#if SQLITE_ENABLE_API_ARMOR +#ifdef SQLITE_ENABLE_API_ARMOR if( ((CheckMutex*)p)->iType<2 ) #endif { @@ -28870,7 +29145,7 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ */ static void pthreadMutexFree(sqlite3_mutex *p){ assert( p->nRef==0 ); -#if SQLITE_ENABLE_API_ARMOR +#ifdef SQLITE_ENABLE_API_ARMOR if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ) #endif { @@ -29223,7 +29498,7 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ SQLITE_MEMORY_BARRIER; #elif defined(__GNUC__) __sync_synchronize(); -#elif MSVC_VERSION>=1300 +#elif MSVC_VERSION>=1400 _ReadWriteBarrier(); #elif defined(MemoryBarrier) MemoryBarrier(); @@ -30434,7 +30709,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ if( db->mallocFailed || rc ){ return apiHandleError(db, rc); } - return rc & db->errMask; + return 0; } /************** End of malloc.c **********************************************/ @@ -31830,7 +32105,7 @@ SQLITE_PRIVATE char *sqlite3RCStrRef(char *z){ ** Decrease the reference count by one. Free the string when the ** reference count reaches zero. */ -SQLITE_PRIVATE void sqlite3RCStrUnref(char *z){ +SQLITE_PRIVATE void sqlite3RCStrUnref(void *z){ RCStr *p = (RCStr*)z; assert( p!=0 ); p--; @@ -32293,6 +32568,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u sqlite3TreeViewItem(pView, "FILTER", 1); sqlite3TreeViewExpr(pView, pWin->pFilter, 0); sqlite3TreeViewPop(&pView); + if( pWin->eFrmType==TK_FILTER ) return; } sqlite3TreeViewPush(&pView, more); if( pWin->zName ){ @@ -32302,7 +32578,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u } if( pWin->zBase ) nElement++; if( pWin->pOrderBy ) nElement++; - if( pWin->eFrmType ) nElement++; + if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ) nElement++; if( pWin->eExclude ) nElement++; if( pWin->zBase ){ sqlite3TreeViewPush(&pView, (--nElement)>0); @@ -32315,7 +32591,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u if( pWin->pOrderBy ){ sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY"); } - if( pWin->eFrmType ){ + if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ){ char zBuf[30]; const char *zFrmType = "ROWS"; if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE"; @@ -32563,7 +32839,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m assert( ExprUseXList(pExpr) ); pFarg = pExpr->x.pList; #ifndef SQLITE_OMIT_WINDOWFUNC - pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0; + pWin = IsWindowFunc(pExpr) ? pExpr->y.pWin : 0; #else pWin = 0; #endif @@ -32589,7 +32865,13 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs); } if( pFarg ){ - sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0); + sqlite3TreeViewExprList(pView, pFarg, pWin!=0 || pExpr->pLeft, 0); + if( pExpr->pLeft ){ + Expr *pOB = pExpr->pLeft; + assert( pOB->op==TK_ORDER ); + assert( ExprUseXList(pOB) ); + sqlite3TreeViewExprList(pView, pOB->x.pList, pWin!=0, "ORDERBY"); + } } #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ @@ -32598,6 +32880,10 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m #endif break; } + case TK_ORDER: { + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, "ORDERBY"); + break; + } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { assert( ExprUseXSelect(pExpr) ); @@ -34362,12 +34648,16 @@ SQLITE_PRIVATE void sqlite3ProgressCheck(Parse *p){ p->rc = SQLITE_INTERRUPT; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK - if( db->xProgress && (++p->nProgressSteps)>=db->nProgressOps ){ - if( db->xProgress(db->pProgressArg) ){ - p->nErr++; - p->rc = SQLITE_INTERRUPT; + if( db->xProgress ){ + if( p->rc==SQLITE_INTERRUPT ){ + p->nProgressSteps = 0; + }else if( (++p->nProgressSteps)>=db->nProgressOps ){ + if( db->xProgress(db->pProgressArg) ){ + p->nErr++; + p->rc = SQLITE_INTERRUPT; + } + p->nProgressSteps = 0; } - p->nProgressSteps = 0; } #endif } @@ -35523,121 +35813,32 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ ** this function assumes the single-byte case has already been handled. */ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){ - u32 a,b; + u64 v64; + u8 n; - /* The 1-byte case. Overwhelmingly the most common. Handled inline - ** by the getVarin32() macro */ - a = *p; - /* a: p0 (unmasked) */ -#ifndef getVarint32 - if (!(a&0x80)) - { - /* Values between 0 and 127 */ - *v = a; - return 1; - } -#endif + /* Assume that the single-byte case has already been handled by + ** the getVarint32() macro */ + assert( (p[0] & 0x80)!=0 ); - /* The 2-byte case */ - p++; - b = *p; - /* b: p1 (unmasked) */ - if (!(b&0x80)) - { - /* Values between 128 and 16383 */ - a &= 0x7f; - a = a<<7; - *v = a | b; + if( (p[1] & 0x80)==0 ){ + /* This is the two-byte case */ + *v = ((p[0]&0x7f)<<7) | p[1]; return 2; } - - /* The 3-byte case */ - p++; - a = a<<14; - a |= *p; - /* a: p0<<14 | p2 (unmasked) */ - if (!(a&0x80)) - { - /* Values between 16384 and 2097151 */ - a &= (0x7f<<14)|(0x7f); - b &= 0x7f; - b = b<<7; - *v = a | b; + if( (p[2] & 0x80)==0 ){ + /* This is the three-byte case */ + *v = ((p[0]&0x7f)<<14) | ((p[1]&0x7f)<<7) | p[2]; return 3; } - - /* A 32-bit varint is used to store size information in btrees. - ** Objects are rarely larger than 2MiB limit of a 3-byte varint. - ** A 3-byte varint is sufficient, for example, to record the size - ** of a 1048569-byte BLOB or string. - ** - ** We only unroll the first 1-, 2-, and 3- byte cases. The very - ** rare larger cases can be handled by the slower 64-bit varint - ** routine. - */ -#if 1 - { - u64 v64; - u8 n; - - n = sqlite3GetVarint(p-2, &v64); - assert( n>3 && n<=9 ); - if( (v64 & SQLITE_MAX_U32)!=v64 ){ - *v = 0xffffffff; - }else{ - *v = (u32)v64; - } - return n; - } - -#else - /* For following code (kept for historical record only) shows an - ** unrolling for the 3- and 4-byte varint cases. This code is - ** slightly faster, but it is also larger and much harder to test. - */ - p++; - b = b<<14; - b |= *p; - /* b: p1<<14 | p3 (unmasked) */ - if (!(b&0x80)) - { - /* Values between 2097152 and 268435455 */ - b &= (0x7f<<14)|(0x7f); - a &= (0x7f<<14)|(0x7f); - a = a<<7; - *v = a | b; - return 4; - } - - p++; - a = a<<14; - a |= *p; - /* a: p0<<28 | p2<<14 | p4 (unmasked) */ - if (!(a&0x80)) - { - /* Values between 268435456 and 34359738367 */ - a &= SLOT_4_2_0; - b &= SLOT_4_2_0; - b = b<<7; - *v = a | b; - return 5; - } - - /* We can only reach this point when reading a corrupt database - ** file. In that case we are not in any hurry. Use the (relatively - ** slow) general-purpose sqlite3GetVarint() routine to extract the - ** value. */ - { - u64 v64; - u8 n; - - p -= 4; - n = sqlite3GetVarint(p, &v64); - assert( n>5 && n<=9 ); + /* four or more bytes */ + n = sqlite3GetVarint(p, &v64); + assert( n>3 && n<=9 ); + if( (v64 & SQLITE_MAX_U32)!=v64 ){ + *v = 0xffffffff; + }else{ *v = (u32)v64; - return n; } -#endif + return n; } /* @@ -36633,19 +36834,20 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 171 */ "VCreate" OpHelp(""), /* 172 */ "VDestroy" OpHelp(""), /* 173 */ "VOpen" OpHelp(""), - /* 174 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), - /* 175 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 176 */ "VRename" OpHelp(""), - /* 177 */ "Pagecount" OpHelp(""), - /* 178 */ "MaxPgcnt" OpHelp(""), - /* 179 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), - /* 180 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), - /* 181 */ "Trace" OpHelp(""), - /* 182 */ "CursorHint" OpHelp(""), - /* 183 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), - /* 184 */ "Noop" OpHelp(""), - /* 185 */ "Explain" OpHelp(""), - /* 186 */ "Abortable" OpHelp(""), + /* 174 */ "VCheck" OpHelp(""), + /* 175 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), + /* 176 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 177 */ "VRename" OpHelp(""), + /* 178 */ "Pagecount" OpHelp(""), + /* 179 */ "MaxPgcnt" OpHelp(""), + /* 180 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), + /* 181 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), + /* 182 */ "Trace" OpHelp(""), + /* 183 */ "CursorHint" OpHelp(""), + /* 184 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), + /* 185 */ "Noop" OpHelp(""), + /* 186 */ "Explain" OpHelp(""), + /* 187 */ "Abortable" OpHelp(""), }; return azName[i]; } @@ -40787,9 +40989,6 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { unixInodeInfo *pInode; afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; int skipShared = 0; -#ifdef SQLITE_TEST - int h = pFile->h; -#endif assert( pFile ); OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock, @@ -40805,9 +41004,6 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); - SimulateIOErrorBenign(1); - SimulateIOError( h=(-1) ) - SimulateIOErrorBenign(0); #ifdef SQLITE_DEBUG /* When reducing a lock such that other processes can start @@ -40856,9 +41052,6 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte; pInode->nShared--; if( pInode->nShared==0 ){ - SimulateIOErrorBenign(1); - SimulateIOError( h=(-1) ) - SimulateIOErrorBenign(0); if( !skipShared ){ rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0); } @@ -57729,9 +57922,32 @@ static int writeJournalHdr(Pager *pPager){ memset(zHeader, 0, sizeof(aJournalMagic)+4); } + + /* The random check-hash initializer */ - sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); + if( pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){ + sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); + } +#ifdef SQLITE_DEBUG + else{ + /* The Pager.cksumInit variable is usually randomized above to protect + ** against there being existing records in the journal file. This is + ** dangerous, as following a crash they may be mistaken for records + ** written by the current transaction and rolled back into the database + ** file, causing corruption. The following assert statements verify + ** that this is not required in "journal_mode=memory" mode, as in that + ** case the journal file is always 0 bytes in size at this point. + ** It is advantageous to avoid the sqlite3_randomness() call if possible + ** as it takes the global PRNG mutex. */ + i64 sz = 0; + sqlite3OsFileSize(pPager->jfd, &sz); + assert( sz==0 ); + assert( pPager->journalOff==journalHdrOffset(pPager) ); + assert( sqlite3JournalIsInMemory(pPager->jfd) ); + } +#endif put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); + /* The initial database size */ put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize); /* The assumed sector size for this process */ @@ -58375,6 +58591,9 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ return (rc==SQLITE_OK?rc2:rc); } +/* Forward reference */ +static int pager_playback(Pager *pPager, int isHot); + /* ** Execute a rollback if a transaction is active and unlock the ** database file. @@ -58403,6 +58622,21 @@ static void pagerUnlockAndRollback(Pager *pPager){ assert( pPager->eState==PAGER_READER ); pager_end_transaction(pPager, 0, 0); } + }else if( pPager->eState==PAGER_ERROR + && pPager->journalMode==PAGER_JOURNALMODE_MEMORY + && isOpen(pPager->jfd) + ){ + /* Special case for a ROLLBACK due to I/O error with an in-memory + ** journal: We have to rollback immediately, before the journal is + ** closed, because once it is closed, all content is forgotten. */ + int errCode = pPager->errCode; + u8 eLock = pPager->eLock; + pPager->eState = PAGER_OPEN; + pPager->errCode = SQLITE_OK; + pPager->eLock = EXCLUSIVE_LOCK; + pager_playback(pPager, 1); + pPager->errCode = errCode; + pPager->eLock = eLock; } pager_unlock(pPager); } @@ -61258,10 +61492,13 @@ SQLITE_PRIVATE int sqlite3PagerOpen( */ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char *zName){ Pager *pPager; + const char *p; while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){ zName--; } - pPager = *(Pager**)(zName - 4 - sizeof(Pager*)); + p = zName - 4 - sizeof(Pager*); + assert( EIGHT_BYTE_ALIGNMENT(p) ); + pPager = *(Pager**)p; return pPager->fd; } @@ -61895,8 +62132,20 @@ SQLITE_PRIVATE int sqlite3PagerGet( DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ - /* printf("PAGE %u\n", pgno); fflush(stdout); */ +#if 0 /* Trace page fetch by setting to 1 */ + int rc; + printf("PAGE %u\n", pgno); + fflush(stdout); + rc = pPager->xGet(pPager, pgno, ppPage, flags); + if( rc ){ + printf("PAGE %u failed with 0x%02x\n", pgno, rc); + fflush(stdout); + } + return rc; +#else + /* Normal, high-speed version of sqlite3PagerGet() */ return pPager->xGet(pPager, pgno, ppPage, flags); +#endif } /* @@ -62772,6 +63021,13 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0); if( rc==SQLITE_OK ){ rc = pager_write_pagelist(pPager, pList); + if( rc==SQLITE_OK && pPager->dbSize>pPager->dbFileSize ){ + char *pTmp = pPager->pTmpSpace; + int szPage = (int)pPager->pageSize; + memset(pTmp, 0, szPage); + rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, + ((i64)pPager->dbSize*pPager->pageSize)-szPage); + } if( rc==SQLITE_OK ){ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0); } @@ -63583,7 +63839,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ } assert( state==pPager->eState ); } - }else if( eMode==PAGER_JOURNALMODE_OFF ){ + }else if( eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_MEMORY ){ sqlite3OsClose(pPager->jfd); } } @@ -69196,7 +69452,7 @@ struct IntegrityCk { BtShared *pBt; /* The tree being checked out */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ u8 *aPgRef; /* 1 bit per page in the db (see above) */ - Pgno nPage; /* Number of pages in the database */ + Pgno nCkPage; /* Pages in the database. 0 for partial check */ int mxErr; /* Stop accumulating errors when this reaches zero */ int nErr; /* Number of messages written to zErrMsg so far */ int rc; /* SQLITE_OK, SQLITE_NOMEM, or SQLITE_INTERRUPT */ @@ -69529,7 +69785,6 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ /************** End of btmutex.c *********************************************/ /************** Begin file btree.c *******************************************/ - /* ** 2004 April 6 ** @@ -77027,7 +77282,7 @@ static int rebuildPage( assert( nCell>0 ); assert( i(u32)usableSize) ){ j = 0; } + if( j>(u32)usableSize ){ j = 0; } memcpy(&pTmp[j], &aData[j], usableSize - j); for(k=0; ALWAYS(kixNx[k]<=i; k++){} @@ -79991,7 +80246,8 @@ static void checkAppendMsg( ** corresponds to page iPg is already set. */ static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){ - assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 ); + assert( pCheck->aPgRef!=0 ); + assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 ); return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07))); } @@ -79999,7 +80255,8 @@ static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){ ** Set the bit in the IntegrityCk.aPgRef[] array that corresponds to page iPg. */ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){ - assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 ); + assert( pCheck->aPgRef!=0 ); + assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 ); pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07)); } @@ -80013,7 +80270,7 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){ ** Also check that the page number is in bounds. */ static int checkRef(IntegrityCk *pCheck, Pgno iPage){ - if( iPage>pCheck->nPage || iPage==0 ){ + if( iPage>pCheck->nCkPage || iPage==0 ){ checkAppendMsg(pCheck, "invalid page number %u", iPage); return 1; } @@ -80240,6 +80497,7 @@ static int checkTreePage( if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){ checkAppendMsg(pCheck, "unable to get the page. error code=%d", rc); + if( rc==SQLITE_IOERR_NOMEM ) pCheck->rc = SQLITE_NOMEM; goto end_of_check; } @@ -80510,15 +80768,15 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( sCheck.db = db; sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; - sCheck.nPage = btreePagecount(sCheck.pBt); + sCheck.nCkPage = btreePagecount(sCheck.pBt); sCheck.mxErr = mxErr; sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH); sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL; - if( sCheck.nPage==0 ){ + if( sCheck.nCkPage==0 ){ goto integrity_ck_cleanup; } - sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1); + sCheck.aPgRef = sqlite3MallocZero((sCheck.nCkPage / 8)+ 1); if( !sCheck.aPgRef ){ checkOom(&sCheck); goto integrity_ck_cleanup; @@ -80530,7 +80788,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( } i = PENDING_BYTE_PAGE(pBt); - if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); + if( i<=sCheck.nCkPage ) setPageReferenced(&sCheck, i); /* Check the integrity of the freelist */ @@ -80581,7 +80839,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( /* Make sure every page in the file is referenced */ if( !bPartial ){ - for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ + for(i=1; i<=sCheck.nCkPage && sCheck.mxErr; i++){ #ifdef SQLITE_OMIT_AUTOVACUUM if( getPageReferenced(&sCheck, i)==0 ){ checkAppendMsg(&sCheck, "Page %u: never used", i); @@ -82022,7 +82280,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ pMem->flags |= MEM_Term; return; } - if( pMem->xDel==(void(*)(void*))sqlite3RCStrUnref ){ + if( pMem->xDel==sqlite3RCStrUnref ){ /* Blindly assume that all RCStr objects are zero-terminated */ pMem->flags |= MEM_Term; return; @@ -83201,7 +83459,7 @@ static int valueFromFunction( #endif assert( pFunc ); if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 - || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) + || (pFunc->funcFlags & (SQLITE_FUNC_NEEDCOLL|SQLITE_FUNC_RUNONLY))!=0 ){ return SQLITE_OK; } @@ -83402,6 +83660,7 @@ static int valueFromExpr( if( pVal ){ pVal->flags = MEM_Int; pVal->u.i = pExpr->u.zToken[4]==0; + sqlite3ValueApplyAffinity(pVal, affinity, enc); } } @@ -83924,10 +84183,11 @@ static int growOpArray(Vdbe *v, int nOp){ ** sqlite3CantopenError(lineno) */ static void test_addop_breakpoint(int pc, Op *pOp){ - static int n = 0; + static u64 n = 0; (void)pc; (void)pOp; n++; + if( n==LARGEST_UINT64 ) abort(); /* so that n is used, preventing a warning */ } #endif @@ -84715,6 +84975,10 @@ SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn( int iDest = pOp->p2; /* Jump destination */ if( iDest==0 ) continue; if( pOp->opcode==OP_Gosub ) continue; + if( pOp->p3==20230325 && pOp->opcode==OP_NotNull ){ + /* This is a deliberately taken illegal branch. tag-20230325-2 */ + continue; + } if( iDest<0 ){ int j = ADDR(iDest); assert( j>=0 ); @@ -88174,20 +88438,33 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem return n1 - n2; } +/* The following two functions are used only within testcase() to prove +** test coverage. These functions do no exist for production builds. +** We must use separate SQLITE_NOINLINE functions here, since otherwise +** optimizer code movement causes gcov to become very confused. +*/ +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) +static int SQLITE_NOINLINE doubleLt(double a, double b){ return a8 ){ + if( sqlite3IsNaN(r) ){ + /* SQLite considers NaN to be a NULL. And all integer values are greater + ** than NULL */ + return 1; + } + if( sqlite3Config.bUseLongDouble ){ LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i; testcase( xr ); testcase( x==r ); - if( xr ) return +1; /*NO_TEST*/ /* work around bugs in gcov */ - return 0; /*NO_TEST*/ /* work around bugs in gcov */ + return (xr); }else{ i64 y; double s; @@ -88197,9 +88474,10 @@ SQLITE_PRIVATE int sqlite3IntFloatCompare(i64 i, double r){ if( iy ) return +1; s = (double)i; - if( sr ) return +1; - return 0; + testcase( doubleLt(s,r) ); + testcase( doubleLt(r,s) ); + testcase( doubleEq(r,s) ); + return (sr); } } @@ -89567,7 +89845,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){ ** is too big or if an OOM occurs. ** ** The invokeValueDestructor(P,X) routine invokes destructor function X() -** on value P is not going to be used and need to be destroyed. +** on value P if P is not going to be used and need to be destroyed. */ static void setResultStrOrError( sqlite3_context *pCtx, /* Function context */ @@ -89597,7 +89875,7 @@ static void setResultStrOrError( static int invokeValueDestructor( const void *p, /* Value to destroy */ void (*xDel)(void*), /* The destructor */ - sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */ + sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if not NULL */ ){ assert( xDel!=SQLITE_DYNAMIC ); if( xDel==0 ){ @@ -89607,7 +89885,14 @@ static int invokeValueDestructor( }else{ xDel((void*)p); } +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx!=0 ){ + sqlite3_result_error_toobig(pCtx); + } +#else + assert( pCtx!=0 ); sqlite3_result_error_toobig(pCtx); +#endif return SQLITE_TOOBIG; } SQLITE_API void sqlite3_result_blob( @@ -89616,6 +89901,12 @@ SQLITE_API void sqlite3_result_blob( int n, void (*xDel)(void *) ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 || n<0 ){ + invokeValueDestructor(z, xDel, pCtx); + return; + } +#endif assert( n>=0 ); assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, 0, xDel); @@ -89626,8 +89917,14 @@ SQLITE_API void sqlite3_result_blob64( sqlite3_uint64 n, void (*xDel)(void *) ){ - assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ){ + invokeValueDestructor(z, xDel, 0); + return; + } +#endif + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); if( n>0x7fffffff ){ (void)invokeValueDestructor(z, xDel, pCtx); }else{ @@ -89635,30 +89932,48 @@ SQLITE_API void sqlite3_result_blob64( } } SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetDouble(pCtx->pOut, rVal); } SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); } #endif SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal); } SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetInt64(pCtx->pOut, iVal); } SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); } @@ -89668,14 +89983,37 @@ SQLITE_API void sqlite3_result_pointer( const char *zPType, void (*xDestructor)(void*) ){ - Mem *pOut = pCtx->pOut; + Mem *pOut; +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ){ + invokeValueDestructor(pPtr, xDestructor, 0); + return; + } +#endif + pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); sqlite3VdbeMemRelease(pOut); pOut->flags = MEM_Null; sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor); } SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ - Mem *pOut = pCtx->pOut; + Mem *pOut; +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif +#if defined(SQLITE_STRICT_SUBTYPE) && SQLITE_STRICT_SUBTYPE+0!=0 + if( pCtx->pFunc!=0 + && (pCtx->pFunc->funcFlags & SQLITE_RESULT_SUBTYPE)==0 + ){ + char zErr[200]; + sqlite3_snprintf(sizeof(zErr), zErr, + "misuse of sqlite3_result_subtype() by %s()", + pCtx->pFunc->zName); + sqlite3_result_error(pCtx, zErr, -1); + return; + } +#endif /* SQLITE_STRICT_SUBTYPE */ + pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); pOut->eSubtype = eSubtype & 0xff; pOut->flags |= MEM_Subtype; @@ -89686,6 +90024,12 @@ SQLITE_API void sqlite3_result_text( int n, void (*xDel)(void *) ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ){ + invokeValueDestructor(z, xDel, 0); + return; + } +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel); } @@ -89696,6 +90040,12 @@ SQLITE_API void sqlite3_result_text64( void (*xDel)(void *), unsigned char enc ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ){ + invokeValueDestructor(z, xDel, 0); + return; + } +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); if( enc!=SQLITE_UTF8 ){ @@ -89739,7 +90089,16 @@ SQLITE_API void sqlite3_result_text16le( } #endif /* SQLITE_OMIT_UTF16 */ SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ - Mem *pOut = pCtx->pOut; + Mem *pOut; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; + if( pValue==0 ){ + sqlite3_result_null(pCtx); + return; + } +#endif + pOut = pCtx->pOut; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemCopy(pOut, pValue); sqlite3VdbeChangeEncoding(pOut, pCtx->enc); @@ -89751,7 +90110,12 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ sqlite3_result_zeroblob64(pCtx, n>0 ? n : 0); } SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ - Mem *pOut = pCtx->pOut; + Mem *pOut; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return SQLITE_MISUSE_BKPT; +#endif + pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(pCtx); @@ -89765,6 +90129,9 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ #endif } SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif pCtx->isError = errCode ? errCode : -1; #ifdef SQLITE_DEBUG if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode; @@ -89777,6 +90144,9 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ /* Force an SQLITE_TOOBIG error. */ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_TOOBIG; sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, @@ -89785,6 +90155,9 @@ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ /* An SQLITE_NOMEM error. */ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); pCtx->isError = SQLITE_NOMEM_BKPT; @@ -90037,7 +90410,11 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ ** pointer to it. */ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 ) return 0; +#else assert( p && p->pFunc ); +#endif return p->pFunc->pUserData; } @@ -90052,7 +90429,11 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ ** application defined function. */ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 ) return 0; +#else assert( p && p->pOut ); +#endif return p->pOut->db; } @@ -90071,7 +90452,11 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ ** value, as a signal to the xUpdate routine that the column is unchanged. */ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 ) return 0; +#else assert( p ); +#endif return sqlite3_value_nochange(p->pOut); } @@ -90099,7 +90484,7 @@ static int valueFromValueList( ValueList *pRhs; *ppOut = 0; - if( pVal==0 ) return SQLITE_MISUSE; + if( pVal==0 ) return SQLITE_MISUSE_BKPT; if( (pVal->flags & MEM_Dyn)==0 || pVal->xDel!=sqlite3VdbeValueListFree ){ return SQLITE_ERROR; }else{ @@ -90230,6 +90615,9 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return 0; +#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); #if SQLITE_ENABLE_STAT4 if( pCtx->pVdbe==0 ) return 0; @@ -90262,8 +90650,12 @@ SQLITE_API void sqlite3_set_auxdata( void (*xDelete)(void*) ){ AuxData *pAuxData; - Vdbe *pVdbe = pCtx->pVdbe; + Vdbe *pVdbe; +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; +#endif + pVdbe= pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); #ifdef SQLITE_ENABLE_STAT4 if( pVdbe==0 ) goto failed; @@ -90700,7 +91092,7 @@ static int vdbeUnbind(Vdbe *p, unsigned int i){ } sqlite3_mutex_enter(p->db->mutex); if( p->eVdbeState!=VDBE_READY_STATE ){ - sqlite3Error(p->db, SQLITE_MISUSE); + sqlite3Error(p->db, SQLITE_MISUSE_BKPT); sqlite3_mutex_leave(p->db->mutex); sqlite3_log(SQLITE_MISUSE, "bind on a busy prepared statement: [%s]", p->zSql); @@ -90929,6 +91321,9 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){ int rc; Vdbe *p = (Vdbe *)pStmt; +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(p->db->mutex); if( n>(u64)p->db->aLimit[SQLITE_LIMIT_LENGTH] ){ rc = SQLITE_TOOBIG; @@ -91055,6 +91450,9 @@ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){ SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode){ Vdbe *v = (Vdbe*)pStmt; int rc; +#ifdef SQLITE_ENABLE_API_ARMOR + if( pStmt==0 ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(v->db->mutex); if( ((int)v->explain)==eMode ){ rc = SQLITE_OK; @@ -91221,10 +91619,16 @@ static UnpackedRecord *vdbeUnpackRecord( ** a field of the row currently being updated or deleted. */ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ - PreUpdate *p = db->pPreUpdate; + PreUpdate *p; Mem *pMem; int rc = SQLITE_OK; +#ifdef SQLITE_ENABLE_API_ARMOR + if( db==0 || ppValue==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + p = db->pPreUpdate; /* Test that this call is being made from within an SQLITE_DELETE or ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */ if( !p || p->op==SQLITE_INSERT ){ @@ -91285,7 +91689,12 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa ** the number of columns in the row being updated, deleted or inserted. */ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ - PreUpdate *p = db->pPreUpdate; + PreUpdate *p; +#ifdef SQLITE_ENABLE_API_ARMOR + p = db!=0 ? db->pPreUpdate : 0; +#else + p = db->pPreUpdate; +#endif return (p ? p->keyinfo.nKeyField : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -91303,7 +91712,12 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ ** or SET DEFAULT action is considered a trigger. */ SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){ - PreUpdate *p = db->pPreUpdate; + PreUpdate *p; +#ifdef SQLITE_ENABLE_API_ARMOR + p = db!=0 ? db->pPreUpdate : 0; +#else + p = db->pPreUpdate; +#endif return (p ? p->v->nFrame : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -91314,7 +91728,12 @@ SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){ ** only. */ SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){ - PreUpdate *p = db->pPreUpdate; + PreUpdate *p; +#ifdef SQLITE_ENABLE_API_ARMOR + p = db!=0 ? db->pPreUpdate : 0; +#else + p = db->pPreUpdate; +#endif return (p ? p->iBlobWrite : -1); } #endif @@ -91325,10 +91744,16 @@ SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){ ** a field of the row currently being updated or inserted. */ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ - PreUpdate *p = db->pPreUpdate; + PreUpdate *p; int rc = SQLITE_OK; Mem *pMem; +#ifdef SQLITE_ENABLE_API_ARMOR + if( db==0 || ppValue==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + p = db->pPreUpdate; if( !p || p->op==SQLITE_DELETE ){ rc = SQLITE_MISUSE_BKPT; goto preupdate_new_out; @@ -91407,11 +91832,20 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2( void *pOut /* OUT: Write the answer here */ ){ Vdbe *p = (Vdbe*)pStmt; - VdbeOp *aOp = p->aOp; - int nOp = p->nOp; + VdbeOp *aOp; + int nOp; ScanStatus *pScan = 0; int idx; +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 || pOut==0 + || iScanStatusOpSQLITE_SCANSTAT_NCYCLE ){ + return 1; + } +#endif + aOp = p->aOp; + nOp = p->nOp; if( p->pFrame ){ VdbeFrame *pFrame; for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); @@ -91558,7 +91992,7 @@ SQLITE_API int sqlite3_stmt_scanstatus( SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; int ii; - for(ii=0; iinOp; ii++){ + for(ii=0; p!=0 && iinOp; ii++){ Op *pOp = &p->aOp[ii]; pOp->nExec = 0; pOp->nCycle = 0; @@ -91897,11 +92331,12 @@ SQLITE_API int sqlite3_found_count = 0; ** sqlite3CantopenError(lineno) */ static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){ - static int n = 0; + static u64 n = 0; (void)pc; (void)pOp; (void)v; n++; + if( n==LARGEST_UINT64 ) abort(); /* So that n is used, preventing a warning */ } #endif @@ -92527,11 +92962,11 @@ static SQLITE_NOINLINE int vdbeColumnFromOverflow( sqlite3RCStrRef(pBuf); if( t&1 ){ rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, encoding, - (void(*)(void*))sqlite3RCStrUnref); + sqlite3RCStrUnref); pDest->flags |= MEM_Term; }else{ rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, 0, - (void(*)(void*))sqlite3RCStrUnref); + sqlite3RCStrUnref); } }else{ rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, iOffset, len, pDest); @@ -95406,7 +95841,6 @@ case OP_MakeRecord: { /* NULL value. No change in zPayload */ }else{ u64 v; - u32 i; if( serial_type==7 ){ assert( sizeof(v)==sizeof(pRec->u.r) ); memcpy(&v, &pRec->u.r, sizeof(v)); @@ -95414,12 +95848,17 @@ case OP_MakeRecord: { }else{ v = pRec->u.i; } - len = i = sqlite3SmallTypeSizes[serial_type]; - assert( i>0 ); - while( 1 /*exit-by-break*/ ){ - zPayload[--i] = (u8)(v&0xFF); - if( i==0 ) break; - v >>= 8; + len = sqlite3SmallTypeSizes[serial_type]; + assert( len>=1 && len<=8 && len!=5 && len!=7 ); + switch( len ){ + default: zPayload[7] = (u8)(v&0xff); v >>= 8; + zPayload[6] = (u8)(v&0xff); v >>= 8; + case 6: zPayload[5] = (u8)(v&0xff); v >>= 8; + zPayload[4] = (u8)(v&0xff); v >>= 8; + case 4: zPayload[3] = (u8)(v&0xff); v >>= 8; + case 3: zPayload[2] = (u8)(v&0xff); v >>= 8; + case 2: zPayload[1] = (u8)(v&0xff); v >>= 8; + case 1: zPayload[0] = (u8)(v&0xff); } zPayload += len; } @@ -97536,8 +97975,13 @@ case OP_RowCell: { ** the "primary" delete. The others are all on OPFLAG_FORDELETE ** cursors or else are marked with the AUXDELETE flag. ** -** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row -** change count is incremented (otherwise not). +** If the OPFLAG_NCHANGE (0x01) flag of P2 (NB: P2 not P5) is set, then +** the row change count is incremented (otherwise not). +** +** If the OPFLAG_ISNOOP (0x40) flag of P2 (not P5!) is set, then the +** pre-update-hook for deletes is run, but the btree is otherwise unchanged. +** This happens when the OP_Delete is to be shortly followed by an OP_Insert +** with the same key, causing the btree entry to be overwritten. ** ** P1 must not be pseudo-table. It has to be a real table with ** multiple rows. @@ -98662,13 +99106,41 @@ case OP_CreateBtree: { /* out2 */ /* Opcode: SqlExec * * * P4 * ** ** Run the SQL statement or statements specified in the P4 string. +** Disable Auth and Trace callbacks while those statements are running if +** P1 is true. */ case OP_SqlExec: { + char *zErr; +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth; +#endif + u8 mTrace; + sqlite3VdbeIncrWriteCounter(p, 0); db->nSqlExec++; - rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0); + zErr = 0; +#ifndef SQLITE_OMIT_AUTHORIZATION + xAuth = db->xAuth; +#endif + mTrace = db->mTrace; + if( pOp->p1 ){ +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = 0; +#endif + db->mTrace = 0; + } + rc = sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr); db->nSqlExec--; - if( rc ) goto abort_due_to_error; +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; +#endif + db->mTrace = mTrace; + if( zErr || rc ){ + sqlite3VdbeError(p, "%s", zErr); + sqlite3_free(zErr); + if( rc==SQLITE_NOMEM ) goto no_mem; + goto abort_due_to_error; + } break; } @@ -99889,6 +100361,53 @@ case OP_VOpen: { /* ncycle */ } #endif /* SQLITE_OMIT_VIRTUALTABLE */ +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VCheck P1 P2 P3 P4 * +** +** P4 is a pointer to a Table object that is a virtual table in schema P1 +** that supports the xIntegrity() method. This opcode runs the xIntegrity() +** method for that virtual table, using P3 as the integer argument. If +** an error is reported back, the table name is prepended to the error +** message and that message is stored in P2. If no errors are seen, +** register P2 is set to NULL. +*/ +case OP_VCheck: { /* out2 */ + Table *pTab; + sqlite3_vtab *pVtab; + const sqlite3_module *pModule; + char *zErr = 0; + + pOut = &aMem[pOp->p2]; + sqlite3VdbeMemSetNull(pOut); /* Innocent until proven guilty */ + assert( pOp->p4type==P4_TABLE ); + pTab = pOp->p4.pTab; + assert( pTab!=0 ); + assert( IsVirtual(pTab) ); + if( pTab->u.vtab.p==0 ) break; + pVtab = pTab->u.vtab.p->pVtab; + assert( pVtab!=0 ); + pModule = pVtab->pModule; + assert( pModule!=0 ); + assert( pModule->iVersion>=4 ); + assert( pModule->xIntegrity!=0 ); + pTab->nTabRef++; + sqlite3VtabLock(pTab->u.vtab.p); + assert( pOp->p1>=0 && pOp->p1nDb ); + rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName, + pOp->p3, &zErr); + sqlite3VtabUnlock(pTab->u.vtab.p); + sqlite3DeleteTable(db, pTab); + if( rc ){ + sqlite3_free(zErr); + goto abort_due_to_error; + } + if( zErr ){ + sqlite3VdbeMemSetStr(pOut, zErr, -1, SQLITE_UTF8, sqlite3_free); + } + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VInitIn P1 P2 P3 * * ** Synopsis: r[P2]=ValueList(P1,P3) @@ -100918,7 +101437,7 @@ SQLITE_API int sqlite3_blob_open( #endif *ppBlob = 0; #ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zTable==0 ){ + if( !sqlite3SafetyCheckOk(db) || zTable==0 || zColumn==0 ){ return SQLITE_MISUSE_BKPT; } #endif @@ -101480,7 +101999,7 @@ struct SorterFile { struct SorterList { SorterRecord *pList; /* Linked list of records */ u8 *aMemory; /* If non-NULL, bulk memory to hold pList */ - int szPMA; /* Size of pList as PMA in bytes */ + i64 szPMA; /* Size of pList as PMA in bytes */ }; /* @@ -101589,10 +102108,10 @@ typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int); struct SortSubtask { SQLiteThread *pThread; /* Background thread, if any */ int bDone; /* Set if thread is finished but not joined */ + int nPMA; /* Number of PMAs currently in file */ VdbeSorter *pSorter; /* Sorter that owns this sub-task */ UnpackedRecord *pUnpacked; /* Space to unpack a record */ SorterList list; /* List for thread to write to a PMA */ - int nPMA; /* Number of PMAs currently in file */ SorterCompare xCompare; /* Compare function to use */ SorterFile file; /* Temp file for level-0 PMAs */ SorterFile file2; /* Space for other PMAs */ @@ -103066,8 +103585,8 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( int rc = SQLITE_OK; /* Return Code */ SorterRecord *pNew; /* New list element */ int bFlush; /* True to flush contents of memory to PMA */ - int nReq; /* Bytes of memory required */ - int nPMA; /* Bytes of PMA space required */ + i64 nReq; /* Bytes of memory required */ + i64 nPMA; /* Bytes of PMA space required */ int t; /* serial type of first record field */ assert( pCsr->eCurType==CURTYPE_SORTER ); @@ -104491,7 +105010,8 @@ static sqlite3_module bytecodevtabModule = { /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, - /* xShadowName */ 0 + /* xShadowName */ 0, + /* xIntegrity */ 0 }; @@ -105320,21 +105840,36 @@ static void resolveAlias( } /* -** Subqueries stores the original database, table and column names for their -** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN". -** Check to see if the zSpan given to this routine matches the zDb, zTab, -** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will -** match anything. +** Subqueries store the original database, table and column names for their +** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN", +** and mark the expression-list item by setting ExprList.a[].fg.eEName +** to ENAME_TAB. +** +** Check to see if the zSpan/eEName of the expression-list item passed to this +** routine matches the zDb, zTab, and zCol. If any of zDb, zTab, and zCol are +** NULL then those fields will match anything. Return true if there is a match, +** or false otherwise. +** +** SF_NestedFrom subqueries also store an entry for the implicit rowid (or +** _rowid_, or oid) column by setting ExprList.a[].fg.eEName to ENAME_ROWID, +** and setting zSpan to "DATABASE.TABLE.". This type of pItem +** argument matches if zCol is a rowid alias. If it is not NULL, (*pbRowid) +** is set to 1 if there is this kind of match. */ SQLITE_PRIVATE int sqlite3MatchEName( const struct ExprList_item *pItem, const char *zCol, const char *zTab, - const char *zDb + const char *zDb, + int *pbRowid ){ int n; const char *zSpan; - if( pItem->fg.eEName!=ENAME_TAB ) return 0; + int eEName = pItem->fg.eEName; + if( eEName!=ENAME_TAB && (eEName!=ENAME_ROWID || NEVER(pbRowid==0)) ){ + return 0; + } + assert( pbRowid==0 || *pbRowid==0 ); zSpan = pItem->zEName; for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){ @@ -105346,9 +105881,11 @@ SQLITE_PRIVATE int sqlite3MatchEName( return 0; } zSpan += n+1; - if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){ - return 0; + if( zCol ){ + if( eEName==ENAME_TAB && sqlite3StrICmp(zSpan, zCol)!=0 ) return 0; + if( eEName==ENAME_ROWID && sqlite3IsRowid(zCol)==0 ) return 0; } + if( eEName==ENAME_ROWID ) *pbRowid = 1; return 1; } @@ -105481,7 +106018,7 @@ static int lookupName( ){ int i, j; /* Loop counters */ int cnt = 0; /* Number of matching column names */ - int cntTab = 0; /* Number of matching table names */ + int cntTab = 0; /* Number of potential "rowid" matches */ int nSubquery = 0; /* How many levels of subquery */ sqlite3 *db = pParse->db; /* The database connection */ SrcItem *pItem; /* Use for looping over pSrcList items */ @@ -105558,39 +106095,49 @@ static int lookupName( assert( pEList!=0 ); assert( pEList->nExpr==pTab->nCol ); for(j=0; jnExpr; j++){ - if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){ + int bRowid = 0; /* True if possible rowid match */ + if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){ continue; } - if( cnt>0 ){ - if( pItem->fg.isUsing==0 - || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 - ){ - /* Two or more tables have the same column name which is - ** not joined by USING. This is an error. Signal as much - ** by clearing pFJMatch and letting cnt go above 1. */ - sqlite3ExprListDelete(db, pFJMatch); - pFJMatch = 0; - }else - if( (pItem->fg.jointype & JT_RIGHT)==0 ){ - /* An INNER or LEFT JOIN. Use the left-most table */ - continue; - }else - if( (pItem->fg.jointype & JT_LEFT)==0 ){ - /* A RIGHT JOIN. Use the right-most table */ - cnt = 0; - sqlite3ExprListDelete(db, pFJMatch); - pFJMatch = 0; - }else{ - /* For a FULL JOIN, we must construct a coalesce() func */ - extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); + if( bRowid==0 ){ + if( cnt>0 ){ + if( pItem->fg.isUsing==0 + || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 + ){ + /* Two or more tables have the same column name which is + ** not joined by USING. This is an error. Signal as much + ** by clearing pFJMatch and letting cnt go above 1. */ + sqlite3ExprListDelete(db, pFJMatch); + pFJMatch = 0; + }else + if( (pItem->fg.jointype & JT_RIGHT)==0 ){ + /* An INNER or LEFT JOIN. Use the left-most table */ + continue; + }else + if( (pItem->fg.jointype & JT_LEFT)==0 ){ + /* A RIGHT JOIN. Use the right-most table */ + cnt = 0; + sqlite3ExprListDelete(db, pFJMatch); + pFJMatch = 0; + }else{ + /* For a FULL JOIN, we must construct a coalesce() func */ + extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); + } } + cnt++; + hit = 1; + }else if( cnt>0 ){ + /* This is a potential rowid match, but there has already been + ** a real match found. So this can be ignored. */ + continue; } - cnt++; - cntTab = 2; + cntTab++; pMatch = pItem; pExpr->iColumn = j; pEList->a[j].fg.bUsed = 1; - hit = 1; + + /* rowid cannot be part of a USING clause - assert() this. */ + assert( bRowid==0 || pEList->a[j].fg.bUsingTerm==0 ); if( pEList->a[j].fg.bUsingTerm ) break; } if( hit || zTab==0 ) continue; @@ -105785,10 +106332,10 @@ static int lookupName( && pMatch && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 && sqlite3IsRowid(zCol) - && ALWAYS(VisibleRowid(pMatch->pTab)) + && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom) ){ cnt = 1; - pExpr->iColumn = -1; + if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1; pExpr->affExpr = SQLITE_AFF_INTEGER; } @@ -106241,6 +106788,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0); #endif assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) ); + assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER ); zId = pExpr->u.zToken; pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0); if( pDef==0 ){ @@ -106382,6 +106930,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pNC->nNcErr++; } #endif + else if( is_agg==0 && pExpr->pLeft ){ + sqlite3ExprOrderByAggregateError(pParse, pExpr); + pNC->nNcErr++; + } if( is_agg ){ /* Window functions may not be arguments of aggregate functions. ** Or arguments of other window functions. But aggregate functions @@ -106400,6 +106952,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif sqlite3WalkExprList(pWalker, pList); if( is_agg ){ + if( pExpr->pLeft ){ + assert( pExpr->pLeft->op==TK_ORDER ); + assert( ExprUseXList(pExpr->pLeft) ); + sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList); + } #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ Select *pSel = pNC->pWinSelect; @@ -106963,10 +107520,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ while( p ){ assert( (p->selFlags & SF_Expanded)!=0 ); assert( (p->selFlags & SF_Resolved)==0 ); - assert( db->suppressErr==0 ); /* SF_Resolved not set if errors suppressed */ p->selFlags |= SF_Resolved; - /* Resolve the expressions in the LIMIT and OFFSET clauses. These ** are not allowed to refer to any names, so pass an empty NameContext. */ @@ -107972,6 +108527,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField( */ pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0); if( pRet ){ + ExprSetProperty(pRet, EP_FullSize); pRet->iTable = nField; pRet->iColumn = iField; pRet->pLeft = pVector; @@ -108562,6 +109118,69 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction( return pNew; } +/* +** Report an error when attempting to use an ORDER BY clause within +** the arguments of a non-aggregate function. +*/ +SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse *pParse, Expr *p){ + sqlite3ErrorMsg(pParse, + "ORDER BY may not be used with non-aggregate %#T()", p + ); +} + +/* +** Attach an ORDER BY clause to a function call. +** +** functionname( arguments ORDER BY sortlist ) +** \_____________________/ \______/ +** pExpr pOrderBy +** +** The ORDER BY clause is inserted into a new Expr node of type TK_ORDER +** and added to the Expr.pLeft field of the parent TK_FUNCTION node. +*/ +SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy( + Parse *pParse, /* Parsing context */ + Expr *pExpr, /* The function call to which ORDER BY is to be added */ + ExprList *pOrderBy /* The ORDER BY clause to add */ +){ + Expr *pOB; + sqlite3 *db = pParse->db; + if( NEVER(pOrderBy==0) ){ + assert( db->mallocFailed ); + return; + } + if( pExpr==0 ){ + assert( db->mallocFailed ); + sqlite3ExprListDelete(db, pOrderBy); + return; + } + assert( pExpr->op==TK_FUNCTION ); + assert( pExpr->pLeft==0 ); + assert( ExprUseXList(pExpr) ); + if( pExpr->x.pList==0 || NEVER(pExpr->x.pList->nExpr==0) ){ + /* Ignore ORDER BY on zero-argument aggregates */ + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3ExprListDelete, + pOrderBy); + return; + } + if( IsWindowFunc(pExpr) ){ + sqlite3ExprOrderByAggregateError(pParse, pExpr); + sqlite3ExprListDelete(db, pOrderBy); + return; + } + + pOB = sqlite3ExprAlloc(db, TK_ORDER, 0, 0); + if( pOB==0 ){ + sqlite3ExprListDelete(db, pOrderBy); + return; + } + pOB->x.pList = pOrderBy; + assert( ExprUseXList(pOB) ); + pExpr->pLeft = pOB; + ExprSetProperty(pOB, EP_FullSize); +} + /* ** Check to see if a function is usable according to current access ** rules: @@ -108815,11 +109434,7 @@ static int dupedExprStructSize(const Expr *p, int flags){ assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ assert( EXPR_FULLSIZE<=0xfff ); assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); - if( 0==flags || p->op==TK_SELECT_COLUMN -#ifndef SQLITE_OMIT_WINDOWFUNC - || ExprHasProperty(p, EP_WinFunc) -#endif - ){ + if( 0==flags || ExprHasProperty(p, EP_FullSize) ){ nSize = EXPR_FULLSIZE; }else{ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); @@ -108850,56 +109465,93 @@ static int dupedExprNodeSize(const Expr *p, int flags){ /* ** Return the number of bytes required to create a duplicate of the -** expression passed as the first argument. The second argument is a -** mask containing EXPRDUP_XXX flags. +** expression passed as the first argument. ** ** The value returned includes space to create a copy of the Expr struct ** itself and the buffer referred to by Expr.u.zToken, if any. ** -** If the EXPRDUP_REDUCE flag is set, then the return value includes -** space to duplicate all Expr nodes in the tree formed by Expr.pLeft -** and Expr.pRight variables (but not for any structures pointed to or -** descended from the Expr.x.pList or Expr.x.pSelect variables). +** The return value includes space to duplicate all Expr nodes in the +** tree formed by Expr.pLeft and Expr.pRight, but not any other +** substructure such as Expr.x.pList, Expr.x.pSelect, and Expr.y.pWin. */ -static int dupedExprSize(const Expr *p, int flags){ - int nByte = 0; - if( p ){ - nByte = dupedExprNodeSize(p, flags); - if( flags&EXPRDUP_REDUCE ){ - nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags); - } - } +static int dupedExprSize(const Expr *p){ + int nByte; + assert( p!=0 ); + nByte = dupedExprNodeSize(p, EXPRDUP_REDUCE); + if( p->pLeft ) nByte += dupedExprSize(p->pLeft); + if( p->pRight ) nByte += dupedExprSize(p->pRight); + assert( nByte==ROUND8(nByte) ); return nByte; } /* -** This function is similar to sqlite3ExprDup(), except that if pzBuffer -** is not NULL then *pzBuffer is assumed to point to a buffer large enough -** to store the copy of expression p, the copies of p->u.zToken -** (if applicable), and the copies of the p->pLeft and p->pRight expressions, -** if any. Before returning, *pzBuffer is set to the first byte past the -** portion of the buffer copied into by this function. +** An EdupBuf is a memory allocation used to stored multiple Expr objects +** together with their Expr.zToken content. This is used to help implement +** compression while doing sqlite3ExprDup(). The top-level Expr does the +** allocation for itself and many of its decendents, then passes an instance +** of the structure down into exprDup() so that they decendents can have +** access to that memory. +*/ +typedef struct EdupBuf EdupBuf; +struct EdupBuf { + u8 *zAlloc; /* Memory space available for storage */ +#ifdef SQLITE_DEBUG + u8 *zEnd; /* First byte past the end of memory */ +#endif +}; + +/* +** This function is similar to sqlite3ExprDup(), except that if pEdupBuf +** is not NULL then it points to memory that can be used to store a copy +** of the input Expr p together with its p->u.zToken (if any). pEdupBuf +** is updated with the new buffer tail prior to returning. */ -static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){ +static Expr *exprDup( + sqlite3 *db, /* Database connection (for memory allocation) */ + const Expr *p, /* Expr tree to be duplicated */ + int dupFlags, /* EXPRDUP_REDUCE for compression. 0 if not */ + EdupBuf *pEdupBuf /* Preallocated storage space, or NULL */ +){ Expr *pNew; /* Value to return */ - u8 *zAlloc; /* Memory space from which to build Expr object */ + EdupBuf sEdupBuf; /* Memory space from which to build Expr object */ u32 staticFlag; /* EP_Static if space not obtained from malloc */ + int nToken = -1; /* Space needed for p->u.zToken. -1 means unknown */ assert( db!=0 ); assert( p ); assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE ); - assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE ); + assert( pEdupBuf==0 || dupFlags==EXPRDUP_REDUCE ); /* Figure out where to write the new Expr structure. */ - if( pzBuffer ){ - zAlloc = *pzBuffer; + if( pEdupBuf ){ + sEdupBuf.zAlloc = pEdupBuf->zAlloc; +#ifdef SQLITE_DEBUG + sEdupBuf.zEnd = pEdupBuf->zEnd; +#endif staticFlag = EP_Static; - assert( zAlloc!=0 ); + assert( sEdupBuf.zAlloc!=0 ); + assert( dupFlags==EXPRDUP_REDUCE ); }else{ - zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags)); + int nAlloc; + if( dupFlags ){ + nAlloc = dupedExprSize(p); + }else if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ + nToken = sqlite3Strlen30NN(p->u.zToken)+1; + nAlloc = ROUND8(EXPR_FULLSIZE + nToken); + }else{ + nToken = 0; + nAlloc = ROUND8(EXPR_FULLSIZE); + } + assert( nAlloc==ROUND8(nAlloc) ); + sEdupBuf.zAlloc = sqlite3DbMallocRawNN(db, nAlloc); +#ifdef SQLITE_DEBUG + sEdupBuf.zEnd = sEdupBuf.zAlloc ? sEdupBuf.zAlloc+nAlloc : 0; +#endif + staticFlag = 0; } - pNew = (Expr *)zAlloc; + pNew = (Expr *)sEdupBuf.zAlloc; + assert( EIGHT_BYTE_ALIGNMENT(pNew) ); if( pNew ){ /* Set nNewSize to the size allocated for the structure pointed to @@ -108908,22 +109560,27 @@ static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){ ** by the copy of the p->u.zToken string (if any). */ const unsigned nStructSize = dupedExprStructSize(p, dupFlags); - const int nNewSize = nStructSize & 0xfff; - int nToken; - if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ - nToken = sqlite3Strlen30(p->u.zToken) + 1; - }else{ - nToken = 0; + int nNewSize = nStructSize & 0xfff; + if( nToken<0 ){ + if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ + nToken = sqlite3Strlen30(p->u.zToken) + 1; + }else{ + nToken = 0; + } } if( dupFlags ){ + assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >= nNewSize+nToken ); assert( ExprHasProperty(p, EP_Reduced)==0 ); - memcpy(zAlloc, p, nNewSize); + memcpy(sEdupBuf.zAlloc, p, nNewSize); }else{ u32 nSize = (u32)exprStructSize(p); - memcpy(zAlloc, p, nSize); + assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >= + (int)EXPR_FULLSIZE+nToken ); + memcpy(sEdupBuf.zAlloc, p, nSize); if( nSizeu.zToken string, if any. */ - if( nToken ){ - char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize]; + assert( nToken>=0 ); + if( nToken>0 ){ + char *zToken = pNew->u.zToken = (char*)&sEdupBuf.zAlloc[nNewSize]; memcpy(zToken, p->u.zToken, nToken); + nNewSize += nToken; } + sEdupBuf.zAlloc += ROUND8(nNewSize); + + if( ((p->flags|pNew->flags)&(EP_TokenOnly|EP_Leaf))==0 ){ - if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ if( ExprUseXSelect(p) ){ pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); }else{ - pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); + pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, + p->op!=TK_ORDER ? dupFlags : 0); } - } - /* Fill in pNew->pLeft and pNew->pRight. */ - if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){ - zAlloc += dupedExprNodeSize(p, dupFlags); - if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){ - pNew->pLeft = p->pLeft ? - exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0; - pNew->pRight = p->pRight ? - exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0; - } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(p, EP_WinFunc) ){ pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin); assert( ExprHasProperty(pNew, EP_WinFunc) ); } #endif /* SQLITE_OMIT_WINDOWFUNC */ - if( pzBuffer ){ - *pzBuffer = zAlloc; - } - }else{ - if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ - if( pNew->op==TK_SELECT_COLUMN ){ + + /* Fill in pNew->pLeft and pNew->pRight. */ + if( dupFlags ){ + if( p->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; - assert( p->pRight==0 || p->pRight==p->pLeft - || ExprHasProperty(p->pLeft, EP_Subquery) ); + assert( p->pRight==0 + || p->pRight==p->pLeft + || ExprHasProperty(p->pLeft, EP_Subquery) ); + }else{ + pNew->pLeft = p->pLeft ? + exprDup(db, p->pLeft, EXPRDUP_REDUCE, &sEdupBuf) : 0; + } + pNew->pRight = p->pRight ? + exprDup(db, p->pRight, EXPRDUP_REDUCE, &sEdupBuf) : 0; + }else{ + if( p->op==TK_SELECT_COLUMN ){ + pNew->pLeft = p->pLeft; + assert( p->pRight==0 + || p->pRight==p->pLeft + || ExprHasProperty(p->pLeft, EP_Subquery) ); }else{ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0); } @@ -108981,6 +109644,8 @@ static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){ } } } + if( pEdupBuf ) memcpy(pEdupBuf, &sEdupBuf, sizeof(sEdupBuf)); + assert( sEdupBuf.zAlloc <= sEdupBuf.zEnd ); return pNew; } @@ -109245,11 +109910,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags) ** initially NULL, then create a new expression list. ** ** The pList argument must be either NULL or a pointer to an ExprList -** obtained from a prior call to sqlite3ExprListAppend(). This routine -** may not be used with an ExprList obtained from sqlite3ExprListDup(). -** Reason: This routine assumes that the number of slots in pList->a[] -** is a power of two. That is true for sqlite3ExprListAppend() returns -** but is not necessarily true from the return value of sqlite3ExprListDup(). +** obtained from a prior call to sqlite3ExprListAppend(). ** ** If a memory allocation error occurs, the entire list is freed and ** NULL is returned. If non-NULL is returned, then it is guaranteed @@ -110075,6 +110736,27 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){ return 0; } +/* +** Return a pointer to a buffer containing a usable rowid alias for table +** pTab. An alias is usable if there is not an explicit user-defined column +** of the same name. +*/ +SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab){ + const char *azOpt[] = {"_ROWID_", "ROWID", "OID"}; + int ii; + assert( VisibleRowid(pTab) ); + for(ii=0; iinCol; iCol++){ + if( sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break; + } + if( iCol==pTab->nCol ){ + return azOpt[ii]; + } + } + return 0; +} + /* ** pX is the RHS of an IN operator. If pX is a SELECT statement ** that can be simplified to a direct table access, then return @@ -111612,6 +112294,41 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( } +/* +** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This +** function checks the Parse.pIdxPartExpr list to see if this column +** can be replaced with a constant value. If so, it generates code to +** put the constant value in a register (ideally, but not necessarily, +** register iTarget) and returns the register number. +** +** Or, if the TK_COLUMN cannot be replaced by a constant, zero is +** returned. +*/ +static int exprPartidxExprLookup(Parse *pParse, Expr *pExpr, int iTarget){ + IndexedExpr *p; + for(p=pParse->pIdxPartExpr; p; p=p->pIENext){ + if( pExpr->iColumn==p->iIdxCol && pExpr->iTable==p->iDataCur ){ + Vdbe *v = pParse->pVdbe; + int addr = 0; + int ret; + + if( p->bMaybeNullRow ){ + addr = sqlite3VdbeAddOp1(v, OP_IfNullRow, p->iIdxCur); + } + ret = sqlite3ExprCodeTarget(pParse, p->pExpr, iTarget); + sqlite3VdbeAddOp4(pParse->pVdbe, OP_Affinity, ret, 1, 0, + (const char*)&p->aff, 1); + if( addr ){ + sqlite3VdbeJumpHere(v, addr); + sqlite3VdbeChangeP3(v, addr, ret); + } + return ret; + } + } + return 0; +} + + /* ** Generate code into the current Vdbe to evaluate the given ** expression. Attempt to store the results in register "target". @@ -111648,6 +112365,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); op = pExpr->op; } + assert( op!=TK_ORDER ); switch( op ){ case TK_AGG_COLUMN: { AggInfo *pAggInfo = pExpr->pAggInfo; @@ -111661,7 +112379,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) #ifdef SQLITE_VDBE_COVERAGE /* Verify that the OP_Null above is exercised by tests ** tag-20230325-2 */ - sqlite3VdbeAddOp2(v, OP_NotNull, target, 1); + sqlite3VdbeAddOp3(v, OP_NotNull, target, 1, 20230325); VdbeCoverageNeverTaken(v); #endif break; @@ -111769,6 +112487,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) iTab = pParse->iSelfTab - 1; } } + else if( pParse->pIdxPartExpr + && 0!=(r1 = exprPartidxExprLookup(pParse, pExpr, target)) + ){ + return r1; + } assert( ExprUseYTab(pExpr) ); assert( pExpr->y.pTab!=0 ); iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab, @@ -112429,7 +113152,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** once. If no functions are involved, then factor the code out and put it at ** the end of the prepared statement in the initialization section. ** -** If regDest>=0 then the result is always stored in that register and the +** If regDest>0 then the result is always stored in that register and the ** result is not reusable. If regDest<0 then this routine is free to ** store the value wherever it wants. The register where the expression ** is stored is returned. When regDest<0, two identical expressions might @@ -112444,6 +113167,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce( ){ ExprList *p; assert( ConstFactorOk(pParse) ); + assert( regDest!=0 ); p = pParse->pConstExpr; if( regDest<0 && p ){ struct ExprList_item *pItem; @@ -113255,8 +113979,8 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB */ SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){ return sqlite3ExprCompare(0, - sqlite3ExprSkipCollateAndLikely(pA), - sqlite3ExprSkipCollateAndLikely(pB), + sqlite3ExprSkipCollate(pA), + sqlite3ExprSkipCollate(pB), iTab); } @@ -113728,6 +114452,12 @@ SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList assert( pExpr->op==TK_AGG_FUNCTION ); assert( ExprUseXList(pExpr) ); sqlite3WalkExprList(&w, pExpr->x.pList); + if( pExpr->pLeft ){ + assert( pExpr->pLeft->op==TK_ORDER ); + assert( ExprUseXList(pExpr->pLeft) ); + assert( pExpr->pLeft->x.pList!=0 ); + sqlite3WalkExprList(&w, pExpr->pLeft->x.pList); + } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter); @@ -113992,14 +114722,42 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ u8 enc = ENC(pParse->db); i = addAggInfoFunc(pParse->db, pAggInfo); if( i>=0 ){ + int nArg; assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); pItem = &pAggInfo->aFunc[i]; pItem->pFExpr = pExpr; assert( ExprUseUToken(pExpr) ); + nArg = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; pItem->pFunc = sqlite3FindFunction(pParse->db, - pExpr->u.zToken, - pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0); - if( pExpr->flags & EP_Distinct ){ + pExpr->u.zToken, nArg, enc, 0); + assert( pItem->bOBUnique==0 ); + if( pExpr->pLeft + && (pItem->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)==0 + ){ + /* The NEEDCOLL test above causes any ORDER BY clause on + ** aggregate min() or max() to be ignored. */ + ExprList *pOBList; + assert( nArg>0 ); + assert( pExpr->pLeft->op==TK_ORDER ); + assert( ExprUseXList(pExpr->pLeft) ); + pItem->iOBTab = pParse->nTab++; + pOBList = pExpr->pLeft->x.pList; + assert( pOBList->nExpr>0 ); + assert( pItem->bOBUnique==0 ); + if( pOBList->nExpr==1 + && nArg==1 + && sqlite3ExprCompare(0,pOBList->a[0].pExpr, + pExpr->x.pList->a[0].pExpr,0)==0 + ){ + pItem->bOBPayload = 0; + pItem->bOBUnique = ExprHasProperty(pExpr, EP_Distinct); + }else{ + pItem->bOBPayload = 1; + } + }else{ + pItem->iOBTab = -1; + } + if( ExprHasProperty(pExpr, EP_Distinct) && !pItem->bOBUnique ){ pItem->iDistinct = pParse->nTab++; }else{ pItem->iDistinct = -1; @@ -114635,14 +115393,19 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ /* Verify that constraints are still satisfied */ if( pNew->pCheck!=0 || (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0) + || (pTab->tabFlags & TF_Strict)!=0 ){ sqlite3NestedParse(pParse, "SELECT CASE WHEN quick_check GLOB 'CHECK*'" " THEN raise(ABORT,'CHECK constraint failed')" + " WHEN quick_check GLOB 'non-* value in*'" + " THEN raise(ABORT,'type mismatch on DEFAULT')" " ELSE raise(ABORT,'NOT NULL constraint failed')" " END" " FROM pragma_quick_check(%Q,%Q)" - " WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'", + " WHERE quick_check GLOB 'CHECK*'" + " OR quick_check GLOB 'NULL*'" + " OR quick_check GLOB 'non-* value in*'", zTab, zDb ); } @@ -119621,19 +120384,14 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ */ if( pParse->pAinc ) sqlite3AutoincrementBegin(pParse); - /* Code constant expressions that where factored out of inner loops. - ** - ** The pConstExpr list might also contain expressions that we simply - ** want to keep around until the Parse object is deleted. Such - ** expressions have iConstExprReg==0. Do not generate code for - ** those expressions, of course. + /* Code constant expressions that were factored out of inner loops. */ if( pParse->pConstExpr ){ ExprList *pEL = pParse->pConstExpr; pParse->okConstFactor = 0; for(i=0; inExpr; i++){ - int iReg = pEL->a[i].u.iConstExprReg; - sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg); + assert( pEL->a[i].u.iConstExprReg>0 ); + sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg); } } @@ -120787,20 +121545,13 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ } #endif -/* -** Name of the special TEMP trigger used to implement RETURNING. The -** name begins with "sqlite_" so that it is guaranteed not to collide -** with any application-generated triggers. -*/ -#define RETURNING_TRIGGER_NAME "sqlite_returning" - /* ** Clean up the data structures associated with the RETURNING clause. */ static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){ Hash *pHash; pHash = &(db->aDb[1].pSchema->trigHash); - sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, 0); + sqlite3HashInsert(pHash, pRet->zName, 0); sqlite3ExprListDelete(db, pRet->pReturnEL); sqlite3DbFree(db, pRet); } @@ -120843,7 +121594,9 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){ (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet); testcase( pParse->earlyCleanup ); if( db->mallocFailed ) return; - pRet->retTrig.zName = RETURNING_TRIGGER_NAME; + sqlite3_snprintf(sizeof(pRet->zName), pRet->zName, + "sqlite_returning_%p", pParse); + pRet->retTrig.zName = pRet->zName; pRet->retTrig.op = TK_RETURNING; pRet->retTrig.tr_tm = TRIGGER_AFTER; pRet->retTrig.bReturning = 1; @@ -120854,9 +121607,9 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){ pRet->retTStep.pTrig = &pRet->retTrig; pRet->retTStep.pExprList = pList; pHash = &(db->aDb[1].pSchema->trigHash); - assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 + assert( sqlite3HashFind(pHash, pRet->zName)==0 || pParse->nErr || pParse->ifNotExists ); - if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig) + if( sqlite3HashInsert(pHash, pRet->zName, &pRet->retTrig) ==&pRet->retTrig ){ sqlite3OomFault(db); } @@ -122300,6 +123053,17 @@ SQLITE_PRIVATE void sqlite3EndTable( /* Reparse everything to update our internal data structures */ sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0); + + /* Test for cycles in generated columns and illegal expressions + ** in CHECK constraints and in DEFAULT clauses. */ + if( p->tabFlags & TF_HasGenerated ){ + sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0, + sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"", + db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC); + } + sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0, + sqlite3MPrintf(db, "PRAGMA \"%w\".integrity_check(%Q)", + db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC); } /* Add the table to the in-memory representation of the database. @@ -127902,7 +128666,8 @@ static void hexFunc( *(z++) = hexdigits[c&0xf]; } *z = 0; - sqlite3_result_text(context, zHex, n*2, sqlite3_free); + sqlite3_result_text64(context, zHex, (u64)(z-zHex), + sqlite3_free, SQLITE_UTF8); } } @@ -128196,6 +128961,81 @@ static void trimFunc( sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); } +/* The core implementation of the CONCAT(...) and CONCAT_WS(SEP,...) +** functions. +** +** Return a string value that is the concatenation of all non-null +** entries in argv[]. Use zSep as the separator. +*/ +static void concatFuncCore( + sqlite3_context *context, + int argc, + sqlite3_value **argv, + int nSep, + const char *zSep +){ + i64 j, k, n = 0; + int i; + char *z; + for(i=0; i0 ){ + const char *v = (const char*)sqlite3_value_text(argv[i]); + if( v!=0 ){ + if( j>0 && nSep>0 ){ + memcpy(&z[j], zSep, nSep); + j += nSep; + } + memcpy(&z[j], v, k); + j += k; + } + } + } + z[j] = 0; + assert( j<=n ); + sqlite3_result_text64(context, z, j, sqlite3_free, SQLITE_UTF8); +} + +/* +** The CONCAT(...) function. Generate a string result that is the +** concatentation of all non-null arguments. +*/ +static void concatFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + concatFuncCore(context, argc, argv, 0, ""); +} + +/* +** The CONCAT_WS(separator, ...) function. +** +** Generate a string that is the concatenation of 2nd through the Nth +** argument. Use the first argument (which must be non-NULL) as the +** separator. +*/ +static void concatwsFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int nSep = sqlite3_value_bytes(argv[0]); + const char *zSep = (const char*)sqlite3_value_text(argv[0]); + if( zSep==0 ) return; + concatFuncCore(context, argc-1, argv+1, nSep, zSep); +} + #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION /* @@ -128617,6 +129457,7 @@ static void minMaxFinalize(sqlite3_context *context){ /* ** group_concat(EXPR, ?SEPARATOR?) +** string_agg(EXPR, SEPARATOR) ** ** The SEPARATOR goes before the EXPR string. This is tragic. The ** groupConcatInverse() implementation would have been easier if the @@ -129207,6 +130048,11 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(hex, 1, 0, 0, hexFunc ), FUNCTION(unhex, 1, 0, 0, unhexFunc ), FUNCTION(unhex, 2, 0, 0, unhexFunc ), + FUNCTION(concat, -1, 0, 0, concatFunc ), + FUNCTION(concat, 0, 0, 0, 0 ), + FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ), + FUNCTION(concat_ws, 0, 0, 0, 0 ), + FUNCTION(concat_ws, 1, 0, 0, 0 ), INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), @@ -129236,6 +130082,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), + WAGGREGATE(string_agg, 2, 0, 0, groupConcatStep, + groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #ifdef SQLITE_CASE_SENSITIVE_LIKE @@ -130178,6 +131026,7 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){ if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull) || (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull) ){ + assert( (pTop->db->flags & SQLITE_FkNoAction)==0 ); return 1; } } @@ -130372,6 +131221,8 @@ SQLITE_PRIVATE void sqlite3FkCheck( } if( regOld!=0 ){ int eAction = pFKey->aAction[aChange!=0]; + if( (db->flags & SQLITE_FkNoAction) ) eAction = OE_None; + fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1); /* If this is a deferred FK constraint, or a CASCADE or SET NULL ** action applies, then any foreign key violations caused by @@ -130487,7 +131338,11 @@ SQLITE_PRIVATE int sqlite3FkRequired( /* Check if any parent key columns are being modified. */ for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ if( fkParentIsModified(pTab, p, aChange, chngRowid) ){ - if( p->aAction[1]!=OE_None ) return 2; + if( (pParse->db->flags & SQLITE_FkNoAction)==0 + && p->aAction[1]!=OE_None + ){ + return 2; + } bHaveFK = 1; } } @@ -130537,6 +131392,7 @@ static Trigger *fkActionTrigger( int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */ action = pFKey->aAction[iAction]; + if( (db->flags & SQLITE_FkNoAction) ) action = OE_None; if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){ return 0; } @@ -134492,6 +135348,9 @@ struct sqlite3_api_routines { int (*is_interrupted)(sqlite3*); /* Version 3.43.0 and later */ int (*stmt_explain)(sqlite3_stmt*,int); + /* Version 3.44.0 and later */ + void *(*get_clientdata)(sqlite3*,const char*); + int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); }; /* @@ -134822,6 +135681,9 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_is_interrupted sqlite3_api->is_interrupted /* Version 3.43.0 and later */ #define sqlite3_stmt_explain sqlite3_api->stmt_explain +/* Version 3.44.0 and later */ +#define sqlite3_get_clientdata sqlite3_api->get_clientdata +#define sqlite3_set_clientdata sqlite3_api->set_clientdata #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -135340,7 +136202,10 @@ static const sqlite3_api_routines sqlite3Apis = { /* Version 3.41.0 and later */ sqlite3_is_interrupted, /* Version 3.43.0 and later */ - sqlite3_stmt_explain + sqlite3_stmt_explain, + /* Version 3.44.0 and later */ + sqlite3_get_clientdata, + sqlite3_set_clientdata }; /* True if x is the directory separator character @@ -135556,6 +136421,9 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){ ** default so as not to open security holes in older applications. */ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); if( onoff ){ db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc; @@ -135605,6 +136473,9 @@ SQLITE_API int sqlite3_auto_extension( void (*xInit)(void) ){ int rc = SQLITE_OK; +#ifdef SQLITE_ENABLE_API_ARMOR + if( xInit==0 ) return SQLITE_MISUSE_BKPT; +#endif #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ){ @@ -135657,6 +136528,9 @@ SQLITE_API int sqlite3_cancel_auto_extension( int i; int n = 0; wsdAutoextInit; +#ifdef SQLITE_ENABLE_API_ARMOR + if( xInit==0 ) return 0; +#endif sqlite3_mutex_enter(mutex); for(i=(int)wsdAutoext.nExt-1; i>=0; i--){ if( wsdAutoext.aExt[i]==xInit ){ @@ -137526,7 +138400,11 @@ SQLITE_PRIVATE void sqlite3Pragma( #endif if( sqlite3GetBoolean(zRight, 0) ){ - db->flags |= mask; + if( (mask & SQLITE_WriteSchema)==0 + || (db->flags & SQLITE_Defensive)==0 + ){ + db->flags |= mask; + } }else{ db->flags &= ~mask; if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; @@ -138159,8 +139037,31 @@ SQLITE_PRIVATE void sqlite3Pragma( int r2; /* Previous key for WITHOUT ROWID tables */ int mxCol; /* Maximum non-virtual column number */ - if( !IsOrdinaryTable(pTab) ) continue; if( pObjTab && pObjTab!=pTab ) continue; + if( !IsOrdinaryTable(pTab) ){ +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3_vtab *pVTab; + int a1; + if( !IsVirtual(pTab) ) continue; + if( pTab->nCol<=0 ){ + const char *zMod = pTab->u.vtab.azArg[0]; + if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue; + } + sqlite3ViewGetColumnNames(pParse, pTab); + if( pTab->u.vtab.p==0 ) continue; + pVTab = pTab->u.vtab.p->pVtab; + if( NEVER(pVTab==0) ) continue; + if( NEVER(pVTab->pModule==0) ) continue; + if( pVTab->pModule->iVersion<4 ) continue; + if( pVTab->pModule->xIntegrity==0 ) continue; + sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick); + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v); + integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, a1); +#endif + continue; + } if( isQuick || HasRowid(pTab) ){ pPk = 0; r2 = 0; @@ -139286,7 +140187,8 @@ static const sqlite3_module pragmaVtabModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0 /* xShadowName */ + 0, /* xShadowName */ + 0 /* xIntegrity */ }; /* @@ -139910,8 +140812,6 @@ SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){ db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue; assert( pParse->db->pParse==pParse ); db->pParse = pParse->pOuterParse; - pParse->db = 0; - pParse->disableLookaside = 0; } /* @@ -140849,6 +141749,7 @@ static void unsetJoinExpr(Expr *p, int iTable, int nullable){ } if( p->op==TK_FUNCTION ){ assert( ExprUseXList(p) ); + assert( p->pLeft==0 ); if( p->x.pList ){ int i; for(i=0; ix.pList->nExpr; i++){ @@ -142713,7 +143614,8 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes( NameContext sNC; assert( pSelect!=0 ); - assert( (pSelect->selFlags & SF_Resolved)!=0 ); + testcase( (pSelect->selFlags & SF_Resolved)==0 ); + assert( (pSelect->selFlags & SF_Resolved)!=0 || IN_RENAME_OBJECT ); assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 ); assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB ); if( db->mallocFailed || IN_RENAME_OBJECT ) return; @@ -146509,6 +147411,7 @@ static int selectExpander(Walker *pWalker, Select *p){ char *zTName = 0; /* text of name of TABLE */ int iErrOfst; if( pE->op==TK_DOT ){ + assert( (selFlags & SF_NestedFrom)==0 ); assert( pE->pLeft!=0 ); assert( !ExprHasProperty(pE->pLeft, EP_IntValue) ); zTName = pE->pLeft->u.zToken; @@ -146519,6 +147422,7 @@ static int selectExpander(Walker *pWalker, Select *p){ iErrOfst = pE->w.iOfst; } for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ + int nAdd; /* Number of cols including rowid */ Table *pTab = pFrom->pTab; /* Table for this data source */ ExprList *pNestedFrom; /* Result-set of a nested FROM clause */ char *zTabName; /* AS name for this data source */ @@ -146536,6 +147440,7 @@ static int selectExpander(Walker *pWalker, Select *p){ pNestedFrom = pFrom->pSelect->pEList; assert( pNestedFrom!=0 ); assert( pNestedFrom->nExpr==pTab->nCol ); + assert( VisibleRowid(pTab)==0 ); }else{ if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; @@ -146566,33 +147471,48 @@ static int selectExpander(Walker *pWalker, Select *p){ }else{ pUsing = 0; } - for(j=0; jnCol; j++){ - char *zName = pTab->aCol[j].zCnName; + + nAdd = pTab->nCol + (VisibleRowid(pTab) && (selFlags&SF_NestedFrom)); + for(j=0; ja[j], 0, zTName, 0)==0 - ){ - continue; - } + if( j==pTab->nCol ){ + zName = sqlite3RowidAlias(pTab); + if( zName==0 ) continue; + }else{ + zName = pTab->aCol[j].zCnName; - /* If a column is marked as 'hidden', omit it from the expanded - ** result-set list unless the SELECT has the SF_IncludeHidden - ** bit set. - */ - if( (p->selFlags & SF_IncludeHidden)==0 - && IsHiddenColumn(&pTab->aCol[j]) - ){ - continue; - } - if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0 - && zTName==0 - && (selFlags & (SF_NestedFrom))==0 - ){ - continue; + /* If pTab is actually an SF_NestedFrom sub-select, do not + ** expand any ENAME_ROWID columns. */ + if( pNestedFrom && pNestedFrom->a[j].fg.eEName==ENAME_ROWID ){ + continue; + } + + if( zTName + && pNestedFrom + && sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0, 0)==0 + ){ + continue; + } + + /* If a column is marked as 'hidden', omit it from the expanded + ** result-set list unless the SELECT has the SF_IncludeHidden + ** bit set. + */ + if( (p->selFlags & SF_IncludeHidden)==0 + && IsHiddenColumn(&pTab->aCol[j]) + ){ + continue; + } + if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0 + && zTName==0 + && (selFlags & (SF_NestedFrom))==0 + ){ + continue; + } } + assert( zName ); tableSeen = 1; if( i>0 && zTName==0 && (selFlags & SF_NestedFrom)==0 ){ @@ -146642,11 +147562,11 @@ static int selectExpander(Walker *pWalker, Select *p){ zSchemaName, zTabName, zName); testcase( pX->zEName==0 ); } - pX->fg.eEName = ENAME_TAB; + pX->fg.eEName = (j==pTab->nCol ? ENAME_ROWID : ENAME_TAB); if( (pFrom->fg.isUsing && sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0) || (pUsing && sqlite3IdListIndex(pUsing, zName)>=0) - || (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0 + || (jnCol && (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)) ){ pX->fg.bNoExpand = 1; } @@ -146748,10 +147668,11 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ SrcList *pTabList; SrcItem *pFrom; - assert( p->selFlags & SF_Resolved ); if( p->selFlags & SF_HasTypeInfo ) return; p->selFlags |= SF_HasTypeInfo; pParse = pWalker->pParse; + testcase( (p->selFlags & SF_Resolved)==0 ); + assert( (p->selFlags & SF_Resolved) || IN_RENAME_OBJECT ); pTabList = p->pSrc; for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; @@ -146867,8 +147788,14 @@ static void analyzeAggFuncArgs( pNC->ncFlags |= NC_InAggFunc; for(i=0; inFunc; i++){ Expr *pExpr = pAggInfo->aFunc[i].pFExpr; + assert( pExpr->op==TK_FUNCTION || pExpr->op==TK_AGG_FUNCTION ); assert( ExprUseXList(pExpr) ); sqlite3ExprAnalyzeAggList(pNC, pExpr->x.pList); + if( pExpr->pLeft ){ + assert( pExpr->pLeft->op==TK_ORDER ); + assert( ExprUseXList(pExpr->pLeft) ); + sqlite3ExprAnalyzeAggList(pNC, pExpr->pLeft->x.pList); + } #ifndef SQLITE_OMIT_WINDOWFUNC assert( !IsWindowFunc(pExpr) ); if( ExprHasProperty(pExpr, EP_WinFunc) ){ @@ -147023,6 +147950,32 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ pFunc->pFunc->zName)); } } + if( pFunc->iOBTab>=0 ){ + ExprList *pOBList; + KeyInfo *pKeyInfo; + int nExtra = 0; + assert( pFunc->pFExpr->pLeft!=0 ); + assert( pFunc->pFExpr->pLeft->op==TK_ORDER ); + assert( ExprUseXList(pFunc->pFExpr->pLeft) ); + pOBList = pFunc->pFExpr->pLeft->x.pList; + if( !pFunc->bOBUnique ){ + nExtra++; /* One extra column for the OP_Sequence */ + } + if( pFunc->bOBPayload ){ + /* extra columns for the function arguments */ + assert( ExprUseXList(pFunc->pFExpr) ); + nExtra += pFunc->pFExpr->x.pList->nExpr; + } + pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra); + if( !pFunc->bOBUnique && pParse->nErr==0 ){ + pKeyInfo->nKeyField++; + } + sqlite3VdbeAddOp4(v, OP_OpenEphemeral, + pFunc->iOBTab, pOBList->nExpr+nExtra, 0, + (char*)pKeyInfo, P4_KEYINFO); + ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(ORDER BY)", + pFunc->pFunc->zName)); + } } } @@ -147038,13 +147991,46 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); pList = pF->pFExpr->x.pList; + if( pF->iOBTab>=0 ){ + /* For an ORDER BY aggregate, calls to OP_AggStep where deferred and + ** all content was stored in emphermal table pF->iOBTab. Extract that + ** content now (in ORDER BY order) and make all calls to OP_AggStep + ** before doing the OP_AggFinal call. */ + int iTop; /* Start of loop for extracting columns */ + int nArg; /* Number of columns to extract */ + int nKey; /* Key columns to be skipped */ + int regAgg; /* Extract into this array */ + int j; /* Loop counter */ + + nArg = pList->nExpr; + regAgg = sqlite3GetTempRange(pParse, nArg); + + if( pF->bOBPayload==0 ){ + nKey = 0; + }else{ + assert( pF->pFExpr->pLeft!=0 ); + assert( ExprUseXList(pF->pFExpr->pLeft) ); + assert( pF->pFExpr->pLeft->x.pList!=0 ); + nKey = pF->pFExpr->pLeft->x.pList->nExpr; + if( ALWAYS(!pF->bOBUnique) ) nKey++; + } + iTop = sqlite3VdbeAddOp1(v, OP_Rewind, pF->iOBTab); VdbeCoverage(v); + for(j=nArg-1; j>=0; j--){ + sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j); + } + sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); + sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, (u8)nArg); + sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, iTop); + sqlite3ReleaseTempRange(pParse, regAgg, nArg); + } sqlite3VdbeAddOp2(v, OP_AggFinal, AggInfoFuncReg(pAggInfo,i), pList ? pList->nExpr : 0); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); } } - /* ** Generate code that will update the accumulator memory cells for an ** aggregate based on the current cursor position. @@ -147053,6 +148039,13 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ ** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator ** registers if register regAcc contains 0. The caller will take care ** of setting and clearing regAcc. +** +** For an ORDER BY aggregate, the actual accumulator memory cell update +** is deferred until after all input rows have been received, so that they +** can be run in the requested order. In that case, instead of invoking +** OP_AggStep to update the accumulator, just add the arguments that would +** have been passed into OP_AggStep into the sorting ephemeral table +** (along with the appropriate sort key). */ static void updateAccumulator( Parse *pParse, @@ -147074,6 +148067,8 @@ static void updateAccumulator( int nArg; int addrNext = 0; int regAgg; + int regAggSz = 0; + int regDistinct = 0; ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); assert( !IsWindowFunc(pF->pFExpr) ); @@ -147100,9 +148095,44 @@ static void updateAccumulator( addrNext = sqlite3VdbeMakeLabel(pParse); sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL); } - if( pList ){ + if( pF->iOBTab>=0 ){ + /* Instead of invoking AggStep, we must push the arguments that would + ** have been passed to AggStep onto the sorting table. */ + int jj; /* Registered used so far in building the record */ + ExprList *pOBList; /* The ORDER BY clause */ + assert( pList!=0 ); + nArg = pList->nExpr; + assert( nArg>0 ); + assert( pF->pFExpr->pLeft!=0 ); + assert( pF->pFExpr->pLeft->op==TK_ORDER ); + assert( ExprUseXList(pF->pFExpr->pLeft) ); + pOBList = pF->pFExpr->pLeft->x.pList; + assert( pOBList!=0 ); + assert( pOBList->nExpr>0 ); + regAggSz = pOBList->nExpr; + if( !pF->bOBUnique ){ + regAggSz++; /* One register for OP_Sequence */ + } + if( pF->bOBPayload ){ + regAggSz += nArg; + } + regAggSz++; /* One extra register to hold result of MakeRecord */ + regAgg = sqlite3GetTempRange(pParse, regAggSz); + regDistinct = regAgg; + sqlite3ExprCodeExprList(pParse, pOBList, regAgg, 0, SQLITE_ECEL_DUP); + jj = pOBList->nExpr; + if( !pF->bOBUnique ){ + sqlite3VdbeAddOp2(v, OP_Sequence, pF->iOBTab, regAgg+jj); + jj++; + } + if( pF->bOBPayload ){ + regDistinct = regAgg+jj; + sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP); + } + }else if( pList ){ nArg = pList->nExpr; regAgg = sqlite3GetTempRange(pParse, nArg); + regDistinct = regAgg; sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP); }else{ nArg = 0; @@ -147113,26 +148143,37 @@ static void updateAccumulator( addrNext = sqlite3VdbeMakeLabel(pParse); } pF->iDistinct = codeDistinct(pParse, eDistinctType, - pF->iDistinct, addrNext, pList, regAgg); - } - if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ - CollSeq *pColl = 0; - struct ExprList_item *pItem; - int j; - assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */ - for(j=0, pItem=pList->a; !pColl && jpExpr); - } - if( !pColl ){ - pColl = pParse->db->pDfltColl; + pF->iDistinct, addrNext, pList, regDistinct); + } + if( pF->iOBTab>=0 ){ + /* Insert a new record into the ORDER BY table */ + sqlite3VdbeAddOp3(v, OP_MakeRecord, regAgg, regAggSz-1, + regAgg+regAggSz-1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pF->iOBTab, regAgg+regAggSz-1, + regAgg, regAggSz-1); + sqlite3ReleaseTempRange(pParse, regAgg, regAggSz); + }else{ + /* Invoke the AggStep function */ + if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ + CollSeq *pColl = 0; + struct ExprList_item *pItem; + int j; + assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */ + for(j=0, pItem=pList->a; !pColl && jpExpr); + } + if( !pColl ){ + pColl = pParse->db->pDfltColl; + } + if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; + sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, + (char *)pColl, P4_COLLSEQ); } - if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; - sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); + sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); + sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, (u8)nArg); + sqlite3ReleaseTempRange(pParse, regAgg, nArg); } - sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); - sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, (u8)nArg); - sqlite3ReleaseTempRange(pParse, regAgg, nArg); if( addrNext ){ sqlite3VdbeResolveLabel(v, addrNext); } @@ -147653,6 +148694,7 @@ SQLITE_PRIVATE int sqlite3Select( TREETRACE(0x1000,pParse,p, ("LEFT-JOIN simplifies to JOIN on term %d\n",i)); pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER); + unsetJoinExpr(p->pWhere, pItem->iCursor, 0); } } if( pItem->fg.jointype & JT_LTORJ ){ @@ -147667,17 +148709,15 @@ SQLITE_PRIVATE int sqlite3Select( TREETRACE(0x1000,pParse,p, ("RIGHT-JOIN simplifies to JOIN on term %d\n",j)); pI2->fg.jointype &= ~(JT_RIGHT|JT_OUTER); + unsetJoinExpr(p->pWhere, pI2->iCursor, 1); } } } - for(j=pTabList->nSrc-1; j>=i; j--){ + for(j=pTabList->nSrc-1; j>=0; j--){ pTabList->a[j].fg.jointype &= ~JT_LTORJ; if( pTabList->a[j].fg.jointype & JT_RIGHT ) break; } } - assert( pItem->iCursor>=0 ); - unsetJoinExpr(p->pWhere, pItem->iCursor, - pTabList->a[0].fg.jointype & JT_LTORJ); } /* No further action if this term of the FROM clause is not a subquery */ @@ -149193,6 +150233,10 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); goto trigger_orphan_error; } + if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){ + sqlite3ErrorMsg(pParse, "cannot create triggers on shadow tables"); + goto trigger_orphan_error; + } /* Check that the trigger name is not reserved and that no trigger of the ** specified name exists */ @@ -149976,10 +151020,17 @@ static void codeReturningTrigger( SrcList sFrom; assert( v!=0 ); - assert( pParse->bReturning ); + if( !pParse->bReturning ){ + /* This RETURNING trigger must be for a different statement as + ** this statement lacks a RETURNING clause. */ + return; + } assert( db->pParse==pParse ); pReturning = pParse->u1.pReturning; - assert( pTrigger == &(pReturning->retTrig) ); + if( pTrigger != &(pReturning->retTrig) ){ + /* This RETURNING trigger is for a different statement */ + return; + } memset(&sSelect, 0, sizeof(sSelect)); memset(&sFrom, 0, sizeof(sFrom)); sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); @@ -153416,7 +154467,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ sqlite3_mutex_enter(db->mutex); pCtx = db->pVtabCtx; if( !pCtx || pCtx->bDeclared ){ - sqlite3Error(db, SQLITE_MISUSE); + sqlite3Error(db, SQLITE_MISUSE_BKPT); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } @@ -154607,7 +155658,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*); #define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */ #define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */ #define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */ -#define WHERE_VIEWSCAN 0x02000000 /* A full-scan of a VIEW or subquery */ + /* 0x02000000 -- available for reuse */ #define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */ #endif /* !defined(SQLITE_WHEREINT_H) */ @@ -160402,13 +161453,17 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( WhereLoop *pLoop = pLevel->pWLoop; /* The loop being coded */ int iCur; /* Cursor for table getting the filter */ IndexedExpr *saved_pIdxEpr; /* saved copy of Parse.pIdxEpr */ + IndexedExpr *saved_pIdxPartExpr; /* saved copy of Parse.pIdxPartExpr */ saved_pIdxEpr = pParse->pIdxEpr; + saved_pIdxPartExpr = pParse->pIdxPartExpr; pParse->pIdxEpr = 0; + pParse->pIdxPartExpr = 0; assert( pLoop!=0 ); assert( v!=0 ); assert( pLoop->wsFlags & WHERE_BLOOMFILTER ); + assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 ); addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); do{ @@ -160498,6 +161553,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( }while( iLevel < pWInfo->nLevel ); sqlite3VdbeJumpHere(v, addrOnce); pParse->pIdxEpr = saved_pIdxEpr; + pParse->pIdxPartExpr = saved_pIdxPartExpr; } @@ -162757,6 +163813,100 @@ static SQLITE_NOINLINE u32 whereIsCoveringIndex( return rc; } +/* +** This is an sqlite3ParserAddCleanup() callback that is invoked to +** free the Parse->pIdxEpr list when the Parse object is destroyed. +*/ +static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){ + IndexedExpr **pp = (IndexedExpr**)pObject; + while( *pp!=0 ){ + IndexedExpr *p = *pp; + *pp = p->pIENext; + sqlite3ExprDelete(db, p->pExpr); + sqlite3DbFreeNN(db, p); + } +} + +/* +** This function is called for a partial index - one with a WHERE clause - in +** two scenarios. In both cases, it determines whether or not the WHERE +** clause on the index implies that a column of the table may be safely +** replaced by a constant expression. For example, in the following +** SELECT: +** +** CREATE INDEX i1 ON t1(b, c) WHERE a=; +** SELECT a, b, c FROM t1 WHERE a= AND b=?; +** +** The "a" in the select-list may be replaced by , iff: +** +** (a) is a constant expression, and +** (b) The (a=) comparison uses the BINARY collation sequence, and +** (c) Column "a" has an affinity other than NONE or BLOB. +** +** If argument pItem is NULL, then pMask must not be NULL. In this case this +** function is being called as part of determining whether or not pIdx +** is a covering index. This function clears any bits in (*pMask) +** corresponding to columns that may be replaced by constants as described +** above. +** +** Otherwise, if pItem is not NULL, then this function is being called +** as part of coding a loop that uses index pIdx. In this case, add entries +** to the Parse.pIdxPartExpr list for each column that can be replaced +** by a constant. +*/ +static void wherePartIdxExpr( + Parse *pParse, /* Parse context */ + Index *pIdx, /* Partial index being processed */ + Expr *pPart, /* WHERE clause being processed */ + Bitmask *pMask, /* Mask to clear bits in */ + int iIdxCur, /* Cursor number for index */ + SrcItem *pItem /* The FROM clause entry for the table */ +){ + assert( pItem==0 || (pItem->fg.jointype & JT_RIGHT)==0 ); + assert( (pItem==0 || pMask==0) && (pMask!=0 || pItem!=0) ); + + if( pPart->op==TK_AND ){ + wherePartIdxExpr(pParse, pIdx, pPart->pRight, pMask, iIdxCur, pItem); + pPart = pPart->pLeft; + } + + if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){ + Expr *pLeft = pPart->pLeft; + Expr *pRight = pPart->pRight; + u8 aff; + + if( pLeft->op!=TK_COLUMN ) return; + if( !sqlite3ExprIsConstant(pRight) ) return; + if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return; + if( pLeft->iColumn<0 ) return; + aff = pIdx->pTable->aCol[pLeft->iColumn].affinity; + if( aff>=SQLITE_AFF_TEXT ){ + if( pItem ){ + sqlite3 *db = pParse->db; + IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocRaw(db, sizeof(*p)); + if( p ){ + int bNullRow = (pItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0; + p->pExpr = sqlite3ExprDup(db, pRight, 0); + p->iDataCur = pItem->iCursor; + p->iIdxCur = iIdxCur; + p->iIdxCol = pLeft->iColumn; + p->bMaybeNullRow = bNullRow; + p->pIENext = pParse->pIdxPartExpr; + p->aff = aff; + pParse->pIdxPartExpr = p; + if( p->pIENext==0 ){ + void *pArg = (void*)&pParse->pIdxPartExpr; + sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg); + } + } + }else if( pLeft->iColumn<(BMS-1) ){ + *pMask &= ~((Bitmask)1 << pLeft->iColumn); + } + } + } +} + + /* ** Add all WhereLoop objects for a single table of the join where the table ** is identified by pBuilder->pNew->iTab. That table is guaranteed to be @@ -162960,9 +164110,6 @@ static int whereLoopAddBtree( #else pNew->rRun = rSize + 16; #endif - if( IsView(pTab) || (pTab->tabFlags & TF_Ephemeral)!=0 ){ - pNew->wsFlags |= WHERE_VIEWSCAN; - } ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); @@ -162975,6 +164122,11 @@ static int whereLoopAddBtree( pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; }else{ m = pSrc->colUsed & pProbe->colNotIdxed; + if( pProbe->pPartIdxWhere ){ + wherePartIdxExpr( + pWInfo->pParse, pProbe, pProbe->pPartIdxWhere, &m, 0, 0 + ); + } pNew->wsFlags = WHERE_INDEXED; if( m==TOPBIT || (pProbe->bHasExpr && !pProbe->bHasVCol && m!=0) ){ u32 isCov = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor); @@ -163357,7 +164509,7 @@ SQLITE_API int sqlite3_vtab_rhs_value( sqlite3_value *pVal = 0; int rc = SQLITE_OK; if( iCons<0 || iCons>=pIdxInfo->nConstraint ){ - rc = SQLITE_MISUSE; /* EV: R-30545-25046 */ + rc = SQLITE_MISUSE_BKPT; /* EV: R-30545-25046 */ }else{ if( pH->aRhs[iCons]==0 ){ WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset]; @@ -164381,14 +165533,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */ } - /* TUNING: A full-scan of a VIEW or subquery in the outer loop - ** is not so bad. */ - if( iLoop==0 && (pWLoop->wsFlags & WHERE_VIEWSCAN)!=0 && nLoop>1 ){ - rCost += -10; - nOut += -30; - WHERETRACE(0x80,("VIEWSCAN cost reduction for %c\n",pWLoop->cId)); - } - /* Check to see if pWLoop should be added to the set of ** mxChoice best-so-far paths. ** @@ -164938,20 +166082,6 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( } } -/* -** This is an sqlite3ParserAddCleanup() callback that is invoked to -** free the Parse->pIdxEpr list when the Parse object is destroyed. -*/ -static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){ - Parse *pParse = (Parse*)pObject; - while( pParse->pIdxEpr!=0 ){ - IndexedExpr *p = pParse->pIdxEpr; - pParse->pIdxEpr = p->pIENext; - sqlite3ExprDelete(db, p->pExpr); - sqlite3DbFreeNN(db, p); - } -} - /* ** The index pIdx is used by a query and contains one or more expressions. ** In other words pIdx is an index on an expression. iIdxCur is the cursor @@ -164991,6 +166121,20 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( continue; } if( sqlite3ExprIsConstant(pExpr) ) continue; + if( pExpr->op==TK_FUNCTION ){ + /* Functions that might set a subtype should not be replaced by the + ** value taken from an expression index since the index omits the + ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */ + int n; + FuncDef *pDef; + sqlite3 *db = pParse->db; + assert( ExprUseXList(pExpr) ); + n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; + pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); + if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ + continue; + } + } p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break; p->pIENext = pParse->pIdxEpr; @@ -165013,7 +166157,8 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( #endif pParse->pIdxEpr = p; if( p->pIENext==0 ){ - sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pParse); + void *pArg = (void*)&pParse->pIdxEpr; + sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg); } } } @@ -165403,6 +166548,16 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( wherePathSolver(pWInfo, pWInfo->nRowOut+1); if( db->mallocFailed ) goto whereBeginError; } + + /* TUNING: Assume that a DISTINCT clause on a subquery reduces + ** the output size by a factor of 8 (LogEst -30). + */ + if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){ + WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n", + pWInfo->nRowOut, pWInfo->nRowOut-30)); + pWInfo->nRowOut -= 30; + } + } assert( pWInfo->pTabList!=0 ); if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ @@ -165615,6 +166770,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( pIx->bHasExpr && OptimizationEnabled(db, SQLITE_IndexedExpr) ){ whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem); } + if( pIx->pPartIdxWhere && (pTabItem->fg.jointype & JT_RIGHT)==0 ){ + wherePartIdxExpr( + pParse, pIx, pIx->pPartIdxWhere, 0, iIndexCur, pTabItem + ); + } } pLevel->iIdxCur = iIndexCur; assert( pIx!=0 ); @@ -167157,7 +168317,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ assert( ExprUseXList(pWin->pOwner) ); assert( pWin->pWFunc!=0 ); pArgs = pWin->pOwner->x.pList; - if( pWin->pWFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){ + if( pWin->pWFunc->funcFlags & SQLITE_SUBTYPE ){ selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist); pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); pWin->bExprArgs = 1; @@ -167431,8 +168591,9 @@ SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ if( p ){ assert( p->op==TK_FUNCTION ); assert( pWin ); + assert( ExprIsFullSize(p) ); p->y.pWin = pWin; - ExprSetProperty(p, EP_WinFunc); + ExprSetProperty(p, EP_WinFunc|EP_FullSize); pWin->pOwner = p; if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){ sqlite3ErrorMsg(pParse, @@ -169734,18 +170895,18 @@ typedef union { #define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse; #define sqlite3ParserCTX_STORE yypParser->pParse=pParse; #define YYFALLBACK 1 -#define YYNSTATE 575 -#define YYNRULE 403 -#define YYNRULE_WITH_ACTION 338 +#define YYNSTATE 579 +#define YYNRULE 405 +#define YYNRULE_WITH_ACTION 340 #define YYNTOKEN 185 -#define YY_MAX_SHIFT 574 -#define YY_MIN_SHIFTREDUCE 833 -#define YY_MAX_SHIFTREDUCE 1235 -#define YY_ERROR_ACTION 1236 -#define YY_ACCEPT_ACTION 1237 -#define YY_NO_ACTION 1238 -#define YY_MIN_REDUCE 1239 -#define YY_MAX_REDUCE 1641 +#define YY_MAX_SHIFT 578 +#define YY_MIN_SHIFTREDUCE 838 +#define YY_MAX_SHIFTREDUCE 1242 +#define YY_ERROR_ACTION 1243 +#define YY_ACCEPT_ACTION 1244 +#define YY_NO_ACTION 1245 +#define YY_MIN_REDUCE 1246 +#define YY_MAX_REDUCE 1650 /************* End control #defines *******************************************/ #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) @@ -169812,218 +170973,218 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (2096) +#define YY_ACTTAB_COUNT (2100) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 568, 208, 568, 118, 115, 229, 568, 118, 115, 229, - /* 10 */ 568, 1310, 377, 1289, 408, 562, 562, 562, 568, 409, - /* 20 */ 378, 1310, 1272, 41, 41, 41, 41, 208, 1520, 71, - /* 30 */ 71, 969, 419, 41, 41, 491, 303, 279, 303, 970, - /* 40 */ 397, 71, 71, 125, 126, 80, 1210, 1210, 1047, 1050, - /* 50 */ 1037, 1037, 123, 123, 124, 124, 124, 124, 476, 409, - /* 60 */ 1237, 1, 1, 574, 2, 1241, 550, 118, 115, 229, - /* 70 */ 317, 480, 146, 480, 524, 118, 115, 229, 529, 1323, - /* 80 */ 417, 523, 142, 125, 126, 80, 1210, 1210, 1047, 1050, - /* 90 */ 1037, 1037, 123, 123, 124, 124, 124, 124, 118, 115, - /* 100 */ 229, 327, 122, 122, 122, 122, 121, 121, 120, 120, - /* 110 */ 120, 119, 116, 444, 284, 284, 284, 284, 442, 442, - /* 120 */ 442, 1559, 376, 1561, 1186, 375, 1157, 565, 1157, 565, - /* 130 */ 409, 1559, 537, 259, 226, 444, 101, 145, 449, 316, - /* 140 */ 559, 240, 122, 122, 122, 122, 121, 121, 120, 120, - /* 150 */ 120, 119, 116, 444, 125, 126, 80, 1210, 1210, 1047, - /* 160 */ 1050, 1037, 1037, 123, 123, 124, 124, 124, 124, 142, - /* 170 */ 294, 1186, 339, 448, 120, 120, 120, 119, 116, 444, - /* 180 */ 127, 1186, 1187, 1186, 148, 441, 440, 568, 119, 116, - /* 190 */ 444, 124, 124, 124, 124, 117, 122, 122, 122, 122, - /* 200 */ 121, 121, 120, 120, 120, 119, 116, 444, 454, 113, - /* 210 */ 13, 13, 546, 122, 122, 122, 122, 121, 121, 120, - /* 220 */ 120, 120, 119, 116, 444, 422, 316, 559, 1186, 1187, - /* 230 */ 1186, 149, 1218, 409, 1218, 124, 124, 124, 124, 122, - /* 240 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116, - /* 250 */ 444, 465, 342, 1034, 1034, 1048, 1051, 125, 126, 80, - /* 260 */ 1210, 1210, 1047, 1050, 1037, 1037, 123, 123, 124, 124, - /* 270 */ 124, 124, 1275, 522, 222, 1186, 568, 409, 224, 514, - /* 280 */ 175, 82, 83, 122, 122, 122, 122, 121, 121, 120, - /* 290 */ 120, 120, 119, 116, 444, 1005, 16, 16, 1186, 133, - /* 300 */ 133, 125, 126, 80, 1210, 1210, 1047, 1050, 1037, 1037, - /* 310 */ 123, 123, 124, 124, 124, 124, 122, 122, 122, 122, - /* 320 */ 121, 121, 120, 120, 120, 119, 116, 444, 1038, 546, - /* 330 */ 1186, 373, 1186, 1187, 1186, 252, 1429, 399, 504, 501, - /* 340 */ 500, 111, 560, 566, 4, 924, 924, 433, 499, 340, - /* 350 */ 460, 328, 360, 394, 1231, 1186, 1187, 1186, 563, 568, - /* 360 */ 122, 122, 122, 122, 121, 121, 120, 120, 120, 119, - /* 370 */ 116, 444, 284, 284, 369, 1572, 1598, 441, 440, 154, - /* 380 */ 409, 445, 71, 71, 1282, 565, 1215, 1186, 1187, 1186, - /* 390 */ 85, 1217, 271, 557, 543, 515, 515, 568, 98, 1216, - /* 400 */ 6, 1274, 472, 142, 125, 126, 80, 1210, 1210, 1047, - /* 410 */ 1050, 1037, 1037, 123, 123, 124, 124, 124, 124, 550, - /* 420 */ 13, 13, 1024, 507, 1218, 1186, 1218, 549, 109, 109, - /* 430 */ 222, 568, 1232, 175, 568, 427, 110, 197, 445, 569, - /* 440 */ 445, 430, 1546, 1014, 325, 551, 1186, 270, 287, 368, - /* 450 */ 510, 363, 509, 257, 71, 71, 543, 71, 71, 359, - /* 460 */ 316, 559, 1604, 122, 122, 122, 122, 121, 121, 120, - /* 470 */ 120, 120, 119, 116, 444, 1014, 1014, 1016, 1017, 27, - /* 480 */ 284, 284, 1186, 1187, 1186, 1152, 568, 1603, 409, 899, - /* 490 */ 190, 550, 356, 565, 550, 935, 533, 517, 1152, 516, - /* 500 */ 413, 1152, 552, 1186, 1187, 1186, 568, 544, 544, 51, - /* 510 */ 51, 214, 125, 126, 80, 1210, 1210, 1047, 1050, 1037, - /* 520 */ 1037, 123, 123, 124, 124, 124, 124, 1186, 474, 135, - /* 530 */ 135, 409, 284, 284, 1484, 505, 121, 121, 120, 120, - /* 540 */ 120, 119, 116, 444, 1005, 565, 518, 217, 541, 541, - /* 550 */ 316, 559, 142, 6, 532, 125, 126, 80, 1210, 1210, - /* 560 */ 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, 124, - /* 570 */ 1548, 122, 122, 122, 122, 121, 121, 120, 120, 120, - /* 580 */ 119, 116, 444, 485, 1186, 1187, 1186, 482, 281, 1263, - /* 590 */ 955, 252, 1186, 373, 504, 501, 500, 1186, 340, 570, - /* 600 */ 1186, 570, 409, 292, 499, 955, 874, 191, 480, 316, - /* 610 */ 559, 384, 290, 380, 122, 122, 122, 122, 121, 121, - /* 620 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1210, - /* 630 */ 1210, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, - /* 640 */ 124, 409, 394, 1132, 1186, 867, 100, 284, 284, 1186, - /* 650 */ 1187, 1186, 373, 1089, 1186, 1187, 1186, 1186, 1187, 1186, - /* 660 */ 565, 455, 32, 373, 233, 125, 126, 80, 1210, 1210, - /* 670 */ 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, 124, - /* 680 */ 1428, 957, 568, 228, 956, 122, 122, 122, 122, 121, - /* 690 */ 121, 120, 120, 120, 119, 116, 444, 1152, 228, 1186, - /* 700 */ 157, 1186, 1187, 1186, 1547, 13, 13, 301, 955, 1226, - /* 710 */ 1152, 153, 409, 1152, 373, 1575, 1170, 5, 369, 1572, - /* 720 */ 429, 1232, 3, 955, 122, 122, 122, 122, 121, 121, - /* 730 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1210, - /* 740 */ 1210, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, - /* 750 */ 124, 409, 208, 567, 1186, 1025, 1186, 1187, 1186, 1186, - /* 760 */ 388, 850, 155, 1546, 286, 402, 1094, 1094, 488, 568, - /* 770 */ 465, 342, 1315, 1315, 1546, 125, 126, 80, 1210, 1210, - /* 780 */ 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, 124, - /* 790 */ 129, 568, 13, 13, 374, 122, 122, 122, 122, 121, - /* 800 */ 121, 120, 120, 120, 119, 116, 444, 302, 568, 453, - /* 810 */ 528, 1186, 1187, 1186, 13, 13, 1186, 1187, 1186, 1293, - /* 820 */ 463, 1263, 409, 1313, 1313, 1546, 1010, 453, 452, 200, - /* 830 */ 299, 71, 71, 1261, 122, 122, 122, 122, 121, 121, - /* 840 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1210, - /* 850 */ 1210, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, - /* 860 */ 124, 409, 227, 1069, 1152, 284, 284, 419, 312, 278, - /* 870 */ 278, 285, 285, 1415, 406, 405, 382, 1152, 565, 568, - /* 880 */ 1152, 1189, 565, 1592, 565, 125, 126, 80, 1210, 1210, - /* 890 */ 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, 124, - /* 900 */ 453, 1476, 13, 13, 1530, 122, 122, 122, 122, 121, - /* 910 */ 121, 120, 120, 120, 119, 116, 444, 201, 568, 354, - /* 920 */ 1578, 574, 2, 1241, 838, 839, 840, 1554, 317, 1205, - /* 930 */ 146, 6, 409, 255, 254, 253, 206, 1323, 9, 1189, - /* 940 */ 262, 71, 71, 424, 122, 122, 122, 122, 121, 121, - /* 950 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1210, - /* 960 */ 1210, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, - /* 970 */ 124, 568, 284, 284, 568, 1206, 409, 573, 313, 1241, - /* 980 */ 349, 1292, 352, 419, 317, 565, 146, 491, 525, 1635, - /* 990 */ 395, 371, 491, 1323, 70, 70, 1291, 71, 71, 240, - /* 1000 */ 1321, 104, 80, 1210, 1210, 1047, 1050, 1037, 1037, 123, - /* 1010 */ 123, 124, 124, 124, 124, 122, 122, 122, 122, 121, - /* 1020 */ 121, 120, 120, 120, 119, 116, 444, 1110, 284, 284, - /* 1030 */ 428, 448, 1519, 1206, 439, 284, 284, 1483, 1348, 311, - /* 1040 */ 474, 565, 1111, 969, 491, 491, 217, 1259, 565, 1532, - /* 1050 */ 568, 970, 207, 568, 1024, 240, 383, 1112, 519, 122, - /* 1060 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116, - /* 1070 */ 444, 1015, 107, 71, 71, 1014, 13, 13, 910, 568, - /* 1080 */ 1489, 568, 284, 284, 97, 526, 491, 448, 911, 1322, - /* 1090 */ 1318, 545, 409, 284, 284, 565, 151, 209, 1489, 1491, - /* 1100 */ 262, 450, 55, 55, 56, 56, 565, 1014, 1014, 1016, - /* 1110 */ 443, 332, 409, 527, 12, 295, 125, 126, 80, 1210, - /* 1120 */ 1210, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, - /* 1130 */ 124, 347, 409, 862, 1528, 1206, 125, 126, 80, 1210, - /* 1140 */ 1210, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, - /* 1150 */ 124, 1133, 1633, 474, 1633, 371, 125, 114, 80, 1210, - /* 1160 */ 1210, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, - /* 1170 */ 124, 1489, 329, 474, 331, 122, 122, 122, 122, 121, - /* 1180 */ 121, 120, 120, 120, 119, 116, 444, 203, 1415, 568, - /* 1190 */ 1290, 862, 464, 1206, 436, 122, 122, 122, 122, 121, - /* 1200 */ 121, 120, 120, 120, 119, 116, 444, 553, 1133, 1634, - /* 1210 */ 539, 1634, 15, 15, 890, 122, 122, 122, 122, 121, - /* 1220 */ 121, 120, 120, 120, 119, 116, 444, 568, 298, 538, - /* 1230 */ 1131, 1415, 1552, 1553, 1327, 409, 6, 6, 1163, 1264, - /* 1240 */ 415, 320, 284, 284, 1415, 508, 565, 525, 300, 457, - /* 1250 */ 43, 43, 568, 891, 12, 565, 330, 478, 425, 407, - /* 1260 */ 126, 80, 1210, 1210, 1047, 1050, 1037, 1037, 123, 123, - /* 1270 */ 124, 124, 124, 124, 568, 57, 57, 288, 1186, 1415, - /* 1280 */ 496, 458, 392, 392, 391, 273, 389, 1131, 1551, 847, - /* 1290 */ 1163, 407, 6, 568, 321, 1152, 470, 44, 44, 1550, - /* 1300 */ 1110, 426, 234, 6, 323, 256, 540, 256, 1152, 431, - /* 1310 */ 568, 1152, 322, 17, 487, 1111, 58, 58, 122, 122, - /* 1320 */ 122, 122, 121, 121, 120, 120, 120, 119, 116, 444, - /* 1330 */ 1112, 216, 481, 59, 59, 1186, 1187, 1186, 111, 560, - /* 1340 */ 324, 4, 236, 456, 526, 568, 237, 456, 568, 437, - /* 1350 */ 168, 556, 420, 141, 479, 563, 568, 293, 568, 1091, - /* 1360 */ 568, 293, 568, 1091, 531, 568, 870, 8, 60, 60, - /* 1370 */ 235, 61, 61, 568, 414, 568, 414, 568, 445, 62, - /* 1380 */ 62, 45, 45, 46, 46, 47, 47, 199, 49, 49, - /* 1390 */ 557, 568, 359, 568, 100, 486, 50, 50, 63, 63, - /* 1400 */ 64, 64, 561, 415, 535, 410, 568, 1024, 568, 534, - /* 1410 */ 316, 559, 316, 559, 65, 65, 14, 14, 568, 1024, - /* 1420 */ 568, 512, 930, 870, 1015, 109, 109, 929, 1014, 66, - /* 1430 */ 66, 131, 131, 110, 451, 445, 569, 445, 416, 177, - /* 1440 */ 1014, 132, 132, 67, 67, 568, 467, 568, 930, 471, - /* 1450 */ 1360, 283, 226, 929, 315, 1359, 407, 568, 459, 407, - /* 1460 */ 1014, 1014, 1016, 239, 407, 86, 213, 1346, 52, 52, - /* 1470 */ 68, 68, 1014, 1014, 1016, 1017, 27, 1577, 1174, 447, - /* 1480 */ 69, 69, 288, 97, 108, 1535, 106, 392, 392, 391, - /* 1490 */ 273, 389, 568, 877, 847, 881, 568, 111, 560, 466, - /* 1500 */ 4, 568, 152, 30, 38, 568, 1128, 234, 396, 323, - /* 1510 */ 111, 560, 527, 4, 563, 53, 53, 322, 568, 163, - /* 1520 */ 163, 568, 337, 468, 164, 164, 333, 563, 76, 76, - /* 1530 */ 568, 289, 1508, 568, 31, 1507, 568, 445, 338, 483, - /* 1540 */ 100, 54, 54, 344, 72, 72, 296, 236, 1076, 557, - /* 1550 */ 445, 877, 1356, 134, 134, 168, 73, 73, 141, 161, - /* 1560 */ 161, 1566, 557, 535, 568, 319, 568, 348, 536, 1007, - /* 1570 */ 473, 261, 261, 889, 888, 235, 535, 568, 1024, 568, - /* 1580 */ 475, 534, 261, 367, 109, 109, 521, 136, 136, 130, - /* 1590 */ 130, 1024, 110, 366, 445, 569, 445, 109, 109, 1014, - /* 1600 */ 162, 162, 156, 156, 568, 110, 1076, 445, 569, 445, - /* 1610 */ 410, 351, 1014, 568, 353, 316, 559, 568, 343, 568, - /* 1620 */ 100, 497, 357, 258, 100, 896, 897, 140, 140, 355, - /* 1630 */ 1306, 1014, 1014, 1016, 1017, 27, 139, 139, 362, 451, - /* 1640 */ 137, 137, 138, 138, 1014, 1014, 1016, 1017, 27, 1174, - /* 1650 */ 447, 568, 372, 288, 111, 560, 1018, 4, 392, 392, - /* 1660 */ 391, 273, 389, 568, 1137, 847, 568, 1072, 568, 258, - /* 1670 */ 492, 563, 568, 211, 75, 75, 555, 960, 234, 261, - /* 1680 */ 323, 111, 560, 927, 4, 113, 77, 77, 322, 74, - /* 1690 */ 74, 42, 42, 1369, 445, 48, 48, 1414, 563, 972, - /* 1700 */ 973, 1088, 1087, 1088, 1087, 860, 557, 150, 928, 1342, - /* 1710 */ 113, 1354, 554, 1419, 1018, 1271, 1262, 1250, 236, 1249, - /* 1720 */ 1251, 445, 1585, 1339, 308, 276, 168, 309, 11, 141, - /* 1730 */ 393, 310, 232, 557, 1401, 1024, 335, 291, 1396, 219, - /* 1740 */ 336, 109, 109, 934, 297, 1406, 235, 341, 477, 110, - /* 1750 */ 502, 445, 569, 445, 1389, 1405, 1014, 400, 1289, 365, - /* 1760 */ 223, 1480, 1024, 1479, 1351, 1352, 1350, 1349, 109, 109, - /* 1770 */ 204, 1588, 1226, 558, 265, 218, 110, 205, 445, 569, - /* 1780 */ 445, 410, 387, 1014, 1527, 179, 316, 559, 1014, 1014, - /* 1790 */ 1016, 1017, 27, 230, 1525, 1223, 79, 560, 85, 4, - /* 1800 */ 418, 215, 548, 81, 84, 188, 1402, 173, 181, 461, - /* 1810 */ 451, 35, 462, 563, 183, 1014, 1014, 1016, 1017, 27, - /* 1820 */ 184, 1485, 185, 186, 495, 242, 98, 398, 1408, 36, - /* 1830 */ 1407, 484, 91, 469, 401, 1410, 445, 192, 1474, 246, - /* 1840 */ 1496, 490, 346, 277, 248, 196, 493, 511, 557, 350, - /* 1850 */ 1252, 249, 250, 403, 1309, 1308, 111, 560, 432, 4, - /* 1860 */ 1307, 1300, 93, 1602, 881, 1601, 224, 404, 434, 520, - /* 1870 */ 263, 435, 1571, 563, 1279, 1278, 364, 1024, 306, 1277, - /* 1880 */ 264, 1600, 1557, 109, 109, 370, 1299, 307, 1556, 438, - /* 1890 */ 128, 110, 1374, 445, 569, 445, 445, 546, 1014, 10, - /* 1900 */ 1461, 105, 381, 1373, 34, 571, 99, 1332, 557, 314, - /* 1910 */ 1180, 530, 272, 274, 379, 210, 1331, 547, 385, 386, - /* 1920 */ 275, 572, 1247, 1242, 411, 412, 1512, 165, 178, 1513, - /* 1930 */ 1014, 1014, 1016, 1017, 27, 1511, 1510, 1024, 78, 147, - /* 1940 */ 166, 220, 221, 109, 109, 834, 304, 167, 446, 212, - /* 1950 */ 318, 110, 231, 445, 569, 445, 144, 1086, 1014, 1084, - /* 1960 */ 326, 180, 169, 1205, 182, 334, 238, 913, 241, 1100, - /* 1970 */ 187, 170, 171, 421, 87, 88, 423, 189, 89, 90, - /* 1980 */ 172, 1103, 243, 1099, 244, 158, 18, 245, 345, 247, - /* 1990 */ 1014, 1014, 1016, 1017, 27, 261, 1092, 193, 1220, 489, - /* 2000 */ 194, 37, 366, 849, 494, 251, 195, 506, 92, 19, - /* 2010 */ 498, 358, 20, 503, 879, 361, 94, 892, 305, 159, - /* 2020 */ 513, 39, 95, 1168, 160, 1053, 964, 1139, 96, 174, - /* 2030 */ 1138, 225, 280, 282, 198, 958, 113, 1158, 1154, 260, - /* 2040 */ 21, 22, 23, 1156, 1162, 1161, 1143, 24, 33, 25, - /* 2050 */ 202, 542, 26, 100, 1067, 102, 1054, 103, 7, 1052, - /* 2060 */ 1056, 1109, 1057, 1108, 266, 267, 28, 40, 390, 1019, - /* 2070 */ 861, 112, 29, 564, 1176, 1175, 268, 176, 143, 923, - /* 2080 */ 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, - /* 2090 */ 1238, 1238, 1238, 1238, 269, 1593, + /* 0 */ 572, 210, 572, 119, 116, 231, 572, 119, 116, 231, + /* 10 */ 572, 1317, 379, 1296, 410, 566, 566, 566, 572, 411, + /* 20 */ 380, 1317, 1279, 42, 42, 42, 42, 210, 1529, 72, + /* 30 */ 72, 974, 421, 42, 42, 495, 305, 281, 305, 975, + /* 40 */ 399, 72, 72, 126, 127, 81, 1217, 1217, 1054, 1057, + /* 50 */ 1044, 1044, 124, 124, 125, 125, 125, 125, 480, 411, + /* 60 */ 1244, 1, 1, 578, 2, 1248, 554, 119, 116, 231, + /* 70 */ 319, 484, 147, 484, 528, 119, 116, 231, 533, 1330, + /* 80 */ 419, 527, 143, 126, 127, 81, 1217, 1217, 1054, 1057, + /* 90 */ 1044, 1044, 124, 124, 125, 125, 125, 125, 119, 116, + /* 100 */ 231, 329, 123, 123, 123, 123, 122, 122, 121, 121, + /* 110 */ 121, 120, 117, 448, 286, 286, 286, 286, 446, 446, + /* 120 */ 446, 1568, 378, 1570, 1193, 377, 1164, 569, 1164, 569, + /* 130 */ 411, 1568, 541, 261, 228, 448, 102, 146, 453, 318, + /* 140 */ 563, 242, 123, 123, 123, 123, 122, 122, 121, 121, + /* 150 */ 121, 120, 117, 448, 126, 127, 81, 1217, 1217, 1054, + /* 160 */ 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, 143, + /* 170 */ 296, 1193, 341, 452, 121, 121, 121, 120, 117, 448, + /* 180 */ 128, 1193, 1194, 1193, 149, 445, 444, 572, 120, 117, + /* 190 */ 448, 125, 125, 125, 125, 118, 123, 123, 123, 123, + /* 200 */ 122, 122, 121, 121, 121, 120, 117, 448, 458, 114, + /* 210 */ 13, 13, 550, 123, 123, 123, 123, 122, 122, 121, + /* 220 */ 121, 121, 120, 117, 448, 424, 318, 563, 1193, 1194, + /* 230 */ 1193, 150, 1225, 411, 1225, 125, 125, 125, 125, 123, + /* 240 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117, + /* 250 */ 448, 469, 344, 1041, 1041, 1055, 1058, 126, 127, 81, + /* 260 */ 1217, 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, + /* 270 */ 125, 125, 1282, 526, 224, 1193, 572, 411, 226, 519, + /* 280 */ 177, 83, 84, 123, 123, 123, 123, 122, 122, 121, + /* 290 */ 121, 121, 120, 117, 448, 1010, 16, 16, 1193, 134, + /* 300 */ 134, 126, 127, 81, 1217, 1217, 1054, 1057, 1044, 1044, + /* 310 */ 124, 124, 125, 125, 125, 125, 123, 123, 123, 123, + /* 320 */ 122, 122, 121, 121, 121, 120, 117, 448, 1045, 550, + /* 330 */ 1193, 375, 1193, 1194, 1193, 254, 1438, 401, 508, 505, + /* 340 */ 504, 112, 564, 570, 4, 929, 929, 435, 503, 342, + /* 350 */ 464, 330, 362, 396, 1238, 1193, 1194, 1193, 567, 572, + /* 360 */ 123, 123, 123, 123, 122, 122, 121, 121, 121, 120, + /* 370 */ 117, 448, 286, 286, 371, 1581, 1607, 445, 444, 155, + /* 380 */ 411, 449, 72, 72, 1289, 569, 1222, 1193, 1194, 1193, + /* 390 */ 86, 1224, 273, 561, 547, 520, 520, 572, 99, 1223, + /* 400 */ 6, 1281, 476, 143, 126, 127, 81, 1217, 1217, 1054, + /* 410 */ 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, 554, + /* 420 */ 13, 13, 1031, 511, 1225, 1193, 1225, 553, 110, 110, + /* 430 */ 224, 572, 1239, 177, 572, 429, 111, 199, 449, 573, + /* 440 */ 449, 432, 1555, 1019, 327, 555, 1193, 272, 289, 370, + /* 450 */ 514, 365, 513, 259, 72, 72, 547, 72, 72, 361, + /* 460 */ 318, 563, 1613, 123, 123, 123, 123, 122, 122, 121, + /* 470 */ 121, 121, 120, 117, 448, 1019, 1019, 1021, 1022, 28, + /* 480 */ 286, 286, 1193, 1194, 1193, 1159, 572, 1612, 411, 904, + /* 490 */ 192, 554, 358, 569, 554, 940, 537, 521, 1159, 437, + /* 500 */ 415, 1159, 556, 1193, 1194, 1193, 572, 548, 548, 52, + /* 510 */ 52, 216, 126, 127, 81, 1217, 1217, 1054, 1057, 1044, + /* 520 */ 1044, 124, 124, 125, 125, 125, 125, 1193, 478, 136, + /* 530 */ 136, 411, 286, 286, 1493, 509, 122, 122, 121, 121, + /* 540 */ 121, 120, 117, 448, 1010, 569, 522, 219, 545, 545, + /* 550 */ 318, 563, 143, 6, 536, 126, 127, 81, 1217, 1217, + /* 560 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, + /* 570 */ 1557, 123, 123, 123, 123, 122, 122, 121, 121, 121, + /* 580 */ 120, 117, 448, 489, 1193, 1194, 1193, 486, 283, 1270, + /* 590 */ 960, 254, 1193, 375, 508, 505, 504, 1193, 342, 574, + /* 600 */ 1193, 574, 411, 294, 503, 960, 879, 193, 484, 318, + /* 610 */ 563, 386, 292, 382, 123, 123, 123, 123, 122, 122, + /* 620 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, + /* 630 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 640 */ 125, 411, 396, 1139, 1193, 872, 101, 286, 286, 1193, + /* 650 */ 1194, 1193, 375, 1096, 1193, 1194, 1193, 1193, 1194, 1193, + /* 660 */ 569, 459, 33, 375, 235, 126, 127, 81, 1217, 1217, + /* 670 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, + /* 680 */ 1437, 962, 572, 230, 961, 123, 123, 123, 123, 122, + /* 690 */ 122, 121, 121, 121, 120, 117, 448, 1159, 230, 1193, + /* 700 */ 158, 1193, 1194, 1193, 1556, 13, 13, 303, 960, 1233, + /* 710 */ 1159, 154, 411, 1159, 375, 1584, 1177, 5, 371, 1581, + /* 720 */ 431, 1239, 3, 960, 123, 123, 123, 123, 122, 122, + /* 730 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, + /* 740 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 750 */ 125, 411, 210, 571, 1193, 1032, 1193, 1194, 1193, 1193, + /* 760 */ 390, 855, 156, 1555, 376, 404, 1101, 1101, 492, 572, + /* 770 */ 469, 344, 1322, 1322, 1555, 126, 127, 81, 1217, 1217, + /* 780 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, + /* 790 */ 130, 572, 13, 13, 532, 123, 123, 123, 123, 122, + /* 800 */ 122, 121, 121, 121, 120, 117, 448, 304, 572, 457, + /* 810 */ 229, 1193, 1194, 1193, 13, 13, 1193, 1194, 1193, 1300, + /* 820 */ 467, 1270, 411, 1320, 1320, 1555, 1015, 457, 456, 436, + /* 830 */ 301, 72, 72, 1268, 123, 123, 123, 123, 122, 122, + /* 840 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, + /* 850 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 860 */ 125, 411, 384, 1076, 1159, 286, 286, 421, 314, 280, + /* 870 */ 280, 287, 287, 461, 408, 407, 1539, 1159, 569, 572, + /* 880 */ 1159, 1196, 569, 409, 569, 126, 127, 81, 1217, 1217, + /* 890 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, + /* 900 */ 457, 1485, 13, 13, 1541, 123, 123, 123, 123, 122, + /* 910 */ 122, 121, 121, 121, 120, 117, 448, 202, 572, 462, + /* 920 */ 1587, 578, 2, 1248, 843, 844, 845, 1563, 319, 409, + /* 930 */ 147, 6, 411, 257, 256, 255, 208, 1330, 9, 1196, + /* 940 */ 264, 72, 72, 1436, 123, 123, 123, 123, 122, 122, + /* 950 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, + /* 960 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 970 */ 125, 572, 286, 286, 572, 1213, 411, 577, 315, 1248, + /* 980 */ 421, 371, 1581, 356, 319, 569, 147, 495, 529, 1644, + /* 990 */ 397, 935, 495, 1330, 71, 71, 934, 72, 72, 242, + /* 1000 */ 1328, 105, 81, 1217, 1217, 1054, 1057, 1044, 1044, 124, + /* 1010 */ 124, 125, 125, 125, 125, 123, 123, 123, 123, 122, + /* 1020 */ 122, 121, 121, 121, 120, 117, 448, 1117, 286, 286, + /* 1030 */ 1422, 452, 1528, 1213, 443, 286, 286, 1492, 1355, 313, + /* 1040 */ 478, 569, 1118, 454, 351, 495, 354, 1266, 569, 209, + /* 1050 */ 572, 418, 179, 572, 1031, 242, 385, 1119, 523, 123, + /* 1060 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117, + /* 1070 */ 448, 1020, 108, 72, 72, 1019, 13, 13, 915, 572, + /* 1080 */ 1498, 572, 286, 286, 98, 530, 1537, 452, 916, 1334, + /* 1090 */ 1329, 203, 411, 286, 286, 569, 152, 211, 1498, 1500, + /* 1100 */ 426, 569, 56, 56, 57, 57, 569, 1019, 1019, 1021, + /* 1110 */ 447, 572, 411, 531, 12, 297, 126, 127, 81, 1217, + /* 1120 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 1130 */ 125, 572, 411, 867, 15, 15, 126, 127, 81, 1217, + /* 1140 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 1150 */ 125, 373, 529, 264, 44, 44, 126, 115, 81, 1217, + /* 1160 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 1170 */ 125, 1498, 478, 1271, 417, 123, 123, 123, 123, 122, + /* 1180 */ 122, 121, 121, 121, 120, 117, 448, 205, 1213, 495, + /* 1190 */ 430, 867, 468, 322, 495, 123, 123, 123, 123, 122, + /* 1200 */ 122, 121, 121, 121, 120, 117, 448, 572, 557, 1140, + /* 1210 */ 1642, 1422, 1642, 543, 572, 123, 123, 123, 123, 122, + /* 1220 */ 122, 121, 121, 121, 120, 117, 448, 572, 1422, 572, + /* 1230 */ 13, 13, 542, 323, 1325, 411, 334, 58, 58, 349, + /* 1240 */ 1422, 1170, 326, 286, 286, 549, 1213, 300, 895, 530, + /* 1250 */ 45, 45, 59, 59, 1140, 1643, 569, 1643, 565, 417, + /* 1260 */ 127, 81, 1217, 1217, 1054, 1057, 1044, 1044, 124, 124, + /* 1270 */ 125, 125, 125, 125, 1367, 373, 500, 290, 1193, 512, + /* 1280 */ 1366, 427, 394, 394, 393, 275, 391, 896, 1138, 852, + /* 1290 */ 478, 258, 1422, 1170, 463, 1159, 12, 331, 428, 333, + /* 1300 */ 1117, 460, 236, 258, 325, 460, 544, 1544, 1159, 1098, + /* 1310 */ 491, 1159, 324, 1098, 440, 1118, 335, 516, 123, 123, + /* 1320 */ 123, 123, 122, 122, 121, 121, 121, 120, 117, 448, + /* 1330 */ 1119, 318, 563, 1138, 572, 1193, 1194, 1193, 112, 564, + /* 1340 */ 201, 4, 238, 433, 935, 490, 285, 228, 1517, 934, + /* 1350 */ 170, 560, 572, 142, 1516, 567, 572, 60, 60, 572, + /* 1360 */ 416, 572, 441, 572, 535, 302, 875, 8, 487, 572, + /* 1370 */ 237, 572, 416, 572, 485, 61, 61, 572, 449, 62, + /* 1380 */ 62, 332, 63, 63, 46, 46, 47, 47, 361, 572, + /* 1390 */ 561, 572, 48, 48, 50, 50, 51, 51, 572, 295, + /* 1400 */ 64, 64, 482, 295, 539, 412, 471, 1031, 572, 538, + /* 1410 */ 318, 563, 65, 65, 66, 66, 409, 475, 572, 1031, + /* 1420 */ 572, 14, 14, 875, 1020, 110, 110, 409, 1019, 572, + /* 1430 */ 474, 67, 67, 111, 455, 449, 573, 449, 98, 317, + /* 1440 */ 1019, 132, 132, 133, 133, 572, 1561, 572, 974, 409, + /* 1450 */ 6, 1562, 68, 68, 1560, 6, 975, 572, 6, 1559, + /* 1460 */ 1019, 1019, 1021, 6, 346, 218, 101, 531, 53, 53, + /* 1470 */ 69, 69, 1019, 1019, 1021, 1022, 28, 1586, 1181, 451, + /* 1480 */ 70, 70, 290, 87, 215, 31, 1363, 394, 394, 393, + /* 1490 */ 275, 391, 350, 109, 852, 107, 572, 112, 564, 483, + /* 1500 */ 4, 1212, 572, 239, 153, 572, 39, 236, 1299, 325, + /* 1510 */ 112, 564, 1298, 4, 567, 572, 32, 324, 572, 54, + /* 1520 */ 54, 572, 1135, 353, 398, 165, 165, 567, 166, 166, + /* 1530 */ 572, 291, 355, 572, 17, 357, 572, 449, 77, 77, + /* 1540 */ 1313, 55, 55, 1297, 73, 73, 572, 238, 470, 561, + /* 1550 */ 449, 472, 364, 135, 135, 170, 74, 74, 142, 163, + /* 1560 */ 163, 374, 561, 539, 572, 321, 572, 886, 540, 137, + /* 1570 */ 137, 339, 1353, 422, 298, 237, 539, 572, 1031, 572, + /* 1580 */ 340, 538, 101, 369, 110, 110, 162, 131, 131, 164, + /* 1590 */ 164, 1031, 111, 368, 449, 573, 449, 110, 110, 1019, + /* 1600 */ 157, 157, 141, 141, 572, 111, 572, 449, 573, 449, + /* 1610 */ 412, 288, 1019, 572, 882, 318, 563, 572, 219, 572, + /* 1620 */ 241, 1012, 477, 263, 263, 894, 893, 140, 140, 138, + /* 1630 */ 138, 1019, 1019, 1021, 1022, 28, 139, 139, 525, 455, + /* 1640 */ 76, 76, 78, 78, 1019, 1019, 1021, 1022, 28, 1181, + /* 1650 */ 451, 572, 1083, 290, 112, 564, 1575, 4, 394, 394, + /* 1660 */ 393, 275, 391, 572, 1023, 852, 572, 479, 345, 263, + /* 1670 */ 101, 567, 882, 1376, 75, 75, 1421, 501, 236, 260, + /* 1680 */ 325, 112, 564, 359, 4, 101, 43, 43, 324, 49, + /* 1690 */ 49, 901, 902, 161, 449, 101, 977, 978, 567, 1079, + /* 1700 */ 1349, 260, 965, 932, 263, 114, 561, 1095, 517, 1095, + /* 1710 */ 1083, 1094, 865, 1094, 151, 933, 1144, 114, 238, 1361, + /* 1720 */ 558, 449, 1023, 559, 1426, 1278, 170, 1269, 1257, 142, + /* 1730 */ 1601, 1256, 1258, 561, 1594, 1031, 496, 278, 213, 1346, + /* 1740 */ 310, 110, 110, 939, 311, 312, 237, 11, 234, 111, + /* 1750 */ 221, 449, 573, 449, 293, 395, 1019, 1408, 337, 1403, + /* 1760 */ 1396, 338, 1031, 299, 343, 1413, 1412, 481, 110, 110, + /* 1770 */ 506, 402, 225, 1296, 206, 367, 111, 1358, 449, 573, + /* 1780 */ 449, 412, 1359, 1019, 1489, 1488, 318, 563, 1019, 1019, + /* 1790 */ 1021, 1022, 28, 562, 207, 220, 80, 564, 389, 4, + /* 1800 */ 1597, 1357, 552, 1356, 1233, 181, 267, 232, 1536, 1534, + /* 1810 */ 455, 1230, 420, 567, 82, 1019, 1019, 1021, 1022, 28, + /* 1820 */ 86, 217, 85, 1494, 190, 175, 183, 465, 185, 466, + /* 1830 */ 36, 1409, 186, 187, 188, 499, 449, 244, 37, 99, + /* 1840 */ 400, 1415, 1414, 488, 1417, 194, 473, 403, 561, 1483, + /* 1850 */ 248, 92, 1505, 494, 198, 279, 112, 564, 250, 4, + /* 1860 */ 348, 497, 405, 352, 1259, 251, 252, 515, 1316, 434, + /* 1870 */ 1315, 1314, 94, 567, 1307, 886, 1306, 1031, 226, 406, + /* 1880 */ 1611, 1610, 438, 110, 110, 1580, 1286, 524, 439, 308, + /* 1890 */ 266, 111, 1285, 449, 573, 449, 449, 309, 1019, 366, + /* 1900 */ 1284, 1609, 265, 1566, 1565, 442, 372, 1381, 561, 129, + /* 1910 */ 550, 1380, 10, 1470, 383, 106, 316, 551, 100, 35, + /* 1920 */ 534, 575, 212, 1339, 381, 387, 1187, 1338, 274, 276, + /* 1930 */ 1019, 1019, 1021, 1022, 28, 277, 413, 1031, 576, 1254, + /* 1940 */ 388, 1521, 1249, 110, 110, 167, 1522, 168, 148, 1520, + /* 1950 */ 1519, 111, 306, 449, 573, 449, 222, 223, 1019, 839, + /* 1960 */ 169, 79, 450, 214, 414, 233, 320, 145, 1093, 1091, + /* 1970 */ 328, 182, 171, 1212, 918, 184, 240, 336, 243, 1107, + /* 1980 */ 189, 172, 173, 423, 425, 88, 180, 191, 89, 90, + /* 1990 */ 1019, 1019, 1021, 1022, 28, 91, 174, 1110, 245, 1106, + /* 2000 */ 246, 159, 18, 247, 347, 1099, 263, 195, 1227, 493, + /* 2010 */ 249, 196, 38, 854, 498, 368, 253, 360, 897, 197, + /* 2020 */ 502, 93, 19, 20, 507, 884, 363, 510, 95, 307, + /* 2030 */ 160, 96, 518, 97, 1175, 1060, 1146, 40, 21, 227, + /* 2040 */ 176, 1145, 282, 284, 969, 200, 963, 114, 262, 1165, + /* 2050 */ 22, 23, 24, 1161, 1169, 25, 1163, 1150, 34, 26, + /* 2060 */ 1168, 546, 27, 204, 101, 103, 104, 1074, 7, 1061, + /* 2070 */ 1059, 1063, 1116, 1064, 1115, 268, 269, 29, 41, 270, + /* 2080 */ 1024, 866, 113, 30, 568, 392, 1183, 144, 178, 1182, + /* 2090 */ 271, 928, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1602, }; static const YYCODETYPE yy_lookahead[] = { /* 0 */ 193, 193, 193, 274, 275, 276, 193, 274, 275, 276, @@ -170102,7 +171263,7 @@ static const YYCODETYPE yy_lookahead[] = { /* 730 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 740 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, /* 750 */ 57, 19, 193, 193, 59, 23, 116, 117, 118, 59, - /* 760 */ 201, 21, 241, 304, 22, 206, 127, 128, 129, 193, + /* 760 */ 201, 21, 241, 304, 193, 206, 127, 128, 129, 193, /* 770 */ 128, 129, 235, 236, 304, 43, 44, 45, 46, 47, /* 780 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, /* 790 */ 22, 193, 216, 217, 193, 102, 103, 104, 105, 106, @@ -170113,129 +171274,129 @@ static const YYCODETYPE yy_lookahead[] = { /* 840 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 850 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, /* 860 */ 57, 19, 193, 123, 76, 239, 240, 193, 253, 239, - /* 870 */ 240, 239, 240, 193, 106, 107, 193, 89, 252, 193, - /* 880 */ 92, 59, 252, 141, 252, 43, 44, 45, 46, 47, + /* 870 */ 240, 239, 240, 244, 106, 107, 193, 89, 252, 193, + /* 880 */ 92, 59, 252, 254, 252, 43, 44, 45, 46, 47, /* 890 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, /* 900 */ 284, 161, 216, 217, 193, 102, 103, 104, 105, 106, - /* 910 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 16, - /* 920 */ 187, 188, 189, 190, 7, 8, 9, 309, 195, 25, + /* 910 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 244, + /* 920 */ 187, 188, 189, 190, 7, 8, 9, 309, 195, 254, /* 930 */ 197, 313, 19, 127, 128, 129, 262, 204, 22, 117, - /* 940 */ 24, 216, 217, 263, 102, 103, 104, 105, 106, 107, + /* 940 */ 24, 216, 217, 273, 102, 103, 104, 105, 106, 107, /* 950 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, /* 970 */ 57, 193, 239, 240, 193, 59, 19, 188, 253, 190, - /* 980 */ 77, 226, 79, 193, 195, 252, 197, 193, 19, 301, - /* 990 */ 302, 193, 193, 204, 216, 217, 226, 216, 217, 266, + /* 980 */ 193, 311, 312, 16, 195, 252, 197, 193, 19, 301, + /* 990 */ 302, 135, 193, 204, 216, 217, 140, 216, 217, 266, /* 1000 */ 204, 159, 45, 46, 47, 48, 49, 50, 51, 52, /* 1010 */ 53, 54, 55, 56, 57, 102, 103, 104, 105, 106, /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 12, 239, 240, - /* 1030 */ 232, 298, 238, 117, 253, 239, 240, 238, 259, 260, - /* 1040 */ 193, 252, 27, 31, 193, 193, 142, 204, 252, 193, - /* 1050 */ 193, 39, 262, 193, 100, 266, 278, 42, 204, 102, + /* 1030 */ 193, 298, 238, 117, 253, 239, 240, 238, 259, 260, + /* 1040 */ 193, 252, 27, 193, 77, 193, 79, 204, 252, 262, + /* 1050 */ 193, 299, 300, 193, 100, 266, 278, 42, 204, 102, /* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, /* 1070 */ 113, 117, 159, 216, 217, 121, 216, 217, 63, 193, - /* 1080 */ 193, 193, 239, 240, 115, 116, 193, 298, 73, 238, + /* 1080 */ 193, 193, 239, 240, 115, 116, 193, 298, 73, 240, /* 1090 */ 238, 231, 19, 239, 240, 252, 22, 24, 211, 212, - /* 1100 */ 24, 193, 216, 217, 216, 217, 252, 153, 154, 155, - /* 1110 */ 253, 16, 19, 144, 213, 268, 43, 44, 45, 46, + /* 1100 */ 263, 252, 216, 217, 216, 217, 252, 153, 154, 155, + /* 1110 */ 253, 193, 19, 144, 213, 268, 43, 44, 45, 46, /* 1120 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1130 */ 57, 238, 19, 59, 193, 59, 43, 44, 45, 46, + /* 1130 */ 57, 193, 19, 59, 216, 217, 43, 44, 45, 46, /* 1140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1150 */ 57, 22, 23, 193, 25, 193, 43, 44, 45, 46, + /* 1150 */ 57, 193, 19, 24, 216, 217, 43, 44, 45, 46, /* 1160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1170 */ 57, 284, 77, 193, 79, 102, 103, 104, 105, 106, - /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 286, 193, 193, - /* 1190 */ 193, 117, 291, 117, 232, 102, 103, 104, 105, 106, - /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 204, 22, 23, - /* 1210 */ 66, 25, 216, 217, 35, 102, 103, 104, 105, 106, - /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 193, 268, 85, - /* 1230 */ 101, 193, 309, 309, 240, 19, 313, 313, 94, 208, - /* 1240 */ 209, 193, 239, 240, 193, 66, 252, 19, 268, 244, - /* 1250 */ 216, 217, 193, 74, 213, 252, 161, 19, 263, 254, + /* 1170 */ 57, 284, 193, 208, 209, 102, 103, 104, 105, 106, + /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 286, 59, 193, + /* 1190 */ 232, 117, 291, 193, 193, 102, 103, 104, 105, 106, + /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 193, 204, 22, + /* 1210 */ 23, 193, 25, 66, 193, 102, 103, 104, 105, 106, + /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 193, 193, 193, + /* 1230 */ 216, 217, 85, 193, 238, 19, 16, 216, 217, 238, + /* 1240 */ 193, 94, 193, 239, 240, 231, 117, 268, 35, 116, + /* 1250 */ 216, 217, 216, 217, 22, 23, 252, 25, 208, 209, /* 1260 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 1270 */ 54, 55, 56, 57, 193, 216, 217, 5, 59, 193, - /* 1280 */ 19, 244, 10, 11, 12, 13, 14, 101, 309, 17, - /* 1290 */ 146, 254, 313, 193, 193, 76, 115, 216, 217, 309, - /* 1300 */ 12, 263, 30, 313, 32, 46, 87, 46, 89, 130, - /* 1310 */ 193, 92, 40, 22, 263, 27, 216, 217, 102, 103, + /* 1270 */ 54, 55, 56, 57, 193, 193, 19, 5, 59, 66, + /* 1280 */ 193, 263, 10, 11, 12, 13, 14, 74, 101, 17, + /* 1290 */ 193, 46, 193, 146, 193, 76, 213, 77, 263, 79, + /* 1300 */ 12, 260, 30, 46, 32, 264, 87, 193, 89, 29, + /* 1310 */ 263, 92, 40, 33, 232, 27, 193, 108, 102, 103, /* 1320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - /* 1330 */ 42, 150, 291, 216, 217, 116, 117, 118, 19, 20, - /* 1340 */ 193, 22, 70, 260, 116, 193, 24, 264, 193, 263, - /* 1350 */ 78, 63, 61, 81, 116, 36, 193, 260, 193, 29, - /* 1360 */ 193, 264, 193, 33, 145, 193, 59, 48, 216, 217, - /* 1370 */ 98, 216, 217, 193, 115, 193, 115, 193, 59, 216, - /* 1380 */ 217, 216, 217, 216, 217, 216, 217, 255, 216, 217, - /* 1390 */ 71, 193, 131, 193, 25, 65, 216, 217, 216, 217, - /* 1400 */ 216, 217, 208, 209, 85, 133, 193, 100, 193, 90, - /* 1410 */ 138, 139, 138, 139, 216, 217, 216, 217, 193, 100, - /* 1420 */ 193, 108, 135, 116, 117, 106, 107, 140, 121, 216, - /* 1430 */ 217, 216, 217, 114, 162, 116, 117, 118, 299, 300, - /* 1440 */ 121, 216, 217, 216, 217, 193, 244, 193, 135, 244, - /* 1450 */ 193, 256, 257, 140, 244, 193, 254, 193, 193, 254, - /* 1460 */ 153, 154, 155, 141, 254, 149, 150, 258, 216, 217, + /* 1330 */ 42, 138, 139, 101, 193, 116, 117, 118, 19, 20, + /* 1340 */ 255, 22, 70, 130, 135, 65, 256, 257, 193, 140, + /* 1350 */ 78, 63, 193, 81, 193, 36, 193, 216, 217, 193, + /* 1360 */ 115, 193, 263, 193, 145, 268, 59, 48, 193, 193, + /* 1370 */ 98, 193, 115, 193, 291, 216, 217, 193, 59, 216, + /* 1380 */ 217, 161, 216, 217, 216, 217, 216, 217, 131, 193, + /* 1390 */ 71, 193, 216, 217, 216, 217, 216, 217, 193, 260, + /* 1400 */ 216, 217, 19, 264, 85, 133, 244, 100, 193, 90, + /* 1410 */ 138, 139, 216, 217, 216, 217, 254, 244, 193, 100, + /* 1420 */ 193, 216, 217, 116, 117, 106, 107, 254, 121, 193, + /* 1430 */ 115, 216, 217, 114, 162, 116, 117, 118, 115, 244, + /* 1440 */ 121, 216, 217, 216, 217, 193, 309, 193, 31, 254, + /* 1450 */ 313, 309, 216, 217, 309, 313, 39, 193, 313, 309, + /* 1460 */ 153, 154, 155, 313, 193, 150, 25, 144, 216, 217, /* 1470 */ 216, 217, 153, 154, 155, 156, 157, 0, 1, 2, - /* 1480 */ 216, 217, 5, 115, 158, 193, 160, 10, 11, 12, - /* 1490 */ 13, 14, 193, 59, 17, 126, 193, 19, 20, 129, - /* 1500 */ 22, 193, 22, 22, 24, 193, 23, 30, 25, 32, - /* 1510 */ 19, 20, 144, 22, 36, 216, 217, 40, 193, 216, - /* 1520 */ 217, 193, 152, 129, 216, 217, 193, 36, 216, 217, - /* 1530 */ 193, 99, 193, 193, 53, 193, 193, 59, 23, 193, - /* 1540 */ 25, 216, 217, 193, 216, 217, 152, 70, 59, 71, - /* 1550 */ 59, 117, 193, 216, 217, 78, 216, 217, 81, 216, - /* 1560 */ 217, 318, 71, 85, 193, 133, 193, 193, 90, 23, - /* 1570 */ 23, 25, 25, 120, 121, 98, 85, 193, 100, 193, - /* 1580 */ 23, 90, 25, 121, 106, 107, 19, 216, 217, 216, + /* 1480 */ 216, 217, 5, 149, 150, 22, 193, 10, 11, 12, + /* 1490 */ 13, 14, 193, 158, 17, 160, 193, 19, 20, 116, + /* 1500 */ 22, 25, 193, 24, 22, 193, 24, 30, 226, 32, + /* 1510 */ 19, 20, 226, 22, 36, 193, 53, 40, 193, 216, + /* 1520 */ 217, 193, 23, 193, 25, 216, 217, 36, 216, 217, + /* 1530 */ 193, 99, 193, 193, 22, 193, 193, 59, 216, 217, + /* 1540 */ 193, 216, 217, 193, 216, 217, 193, 70, 129, 71, + /* 1550 */ 59, 129, 193, 216, 217, 78, 216, 217, 81, 216, + /* 1560 */ 217, 193, 71, 85, 193, 133, 193, 126, 90, 216, + /* 1570 */ 217, 152, 258, 61, 152, 98, 85, 193, 100, 193, + /* 1580 */ 23, 90, 25, 121, 106, 107, 23, 216, 217, 216, /* 1590 */ 217, 100, 114, 131, 116, 117, 118, 106, 107, 121, - /* 1600 */ 216, 217, 216, 217, 193, 114, 117, 116, 117, 118, - /* 1610 */ 133, 193, 121, 193, 193, 138, 139, 193, 23, 193, - /* 1620 */ 25, 23, 23, 25, 25, 7, 8, 216, 217, 193, - /* 1630 */ 193, 153, 154, 155, 156, 157, 216, 217, 193, 162, + /* 1600 */ 216, 217, 216, 217, 193, 114, 193, 116, 117, 118, + /* 1610 */ 133, 22, 121, 193, 59, 138, 139, 193, 142, 193, + /* 1620 */ 141, 23, 23, 25, 25, 120, 121, 216, 217, 216, + /* 1630 */ 217, 153, 154, 155, 156, 157, 216, 217, 19, 162, /* 1640 */ 216, 217, 216, 217, 153, 154, 155, 156, 157, 1, - /* 1650 */ 2, 193, 193, 5, 19, 20, 59, 22, 10, 11, - /* 1660 */ 12, 13, 14, 193, 97, 17, 193, 23, 193, 25, - /* 1670 */ 288, 36, 193, 242, 216, 217, 236, 23, 30, 25, + /* 1650 */ 2, 193, 59, 5, 19, 20, 318, 22, 10, 11, + /* 1660 */ 12, 13, 14, 193, 59, 17, 193, 23, 23, 25, + /* 1670 */ 25, 36, 117, 193, 216, 217, 193, 23, 30, 25, /* 1680 */ 32, 19, 20, 23, 22, 25, 216, 217, 40, 216, - /* 1690 */ 217, 216, 217, 193, 59, 216, 217, 193, 36, 83, - /* 1700 */ 84, 153, 153, 155, 155, 23, 71, 25, 23, 193, - /* 1710 */ 25, 193, 193, 193, 117, 193, 193, 193, 70, 193, - /* 1720 */ 193, 59, 193, 255, 255, 287, 78, 255, 243, 81, - /* 1730 */ 191, 255, 297, 71, 271, 100, 293, 245, 267, 214, - /* 1740 */ 246, 106, 107, 108, 246, 271, 98, 245, 293, 114, - /* 1750 */ 220, 116, 117, 118, 267, 271, 121, 271, 225, 219, - /* 1760 */ 229, 219, 100, 219, 259, 259, 259, 259, 106, 107, - /* 1770 */ 249, 196, 60, 280, 141, 243, 114, 249, 116, 117, - /* 1780 */ 118, 133, 245, 121, 200, 297, 138, 139, 153, 154, - /* 1790 */ 155, 156, 157, 297, 200, 38, 19, 20, 151, 22, - /* 1800 */ 200, 150, 140, 294, 294, 22, 272, 43, 234, 18, - /* 1810 */ 162, 270, 200, 36, 237, 153, 154, 155, 156, 157, - /* 1820 */ 237, 283, 237, 237, 18, 199, 149, 246, 272, 270, - /* 1830 */ 272, 200, 158, 246, 246, 234, 59, 234, 246, 199, - /* 1840 */ 290, 62, 289, 200, 199, 22, 221, 115, 71, 200, - /* 1850 */ 200, 199, 199, 221, 218, 218, 19, 20, 64, 22, - /* 1860 */ 218, 227, 22, 224, 126, 224, 165, 221, 24, 305, - /* 1870 */ 200, 113, 312, 36, 218, 220, 218, 100, 282, 218, - /* 1880 */ 91, 218, 317, 106, 107, 221, 227, 282, 317, 82, - /* 1890 */ 148, 114, 265, 116, 117, 118, 59, 145, 121, 22, - /* 1900 */ 277, 158, 200, 265, 25, 202, 147, 250, 71, 279, - /* 1910 */ 13, 146, 194, 194, 249, 248, 250, 140, 247, 246, - /* 1920 */ 6, 192, 192, 192, 303, 303, 213, 207, 300, 213, - /* 1930 */ 153, 154, 155, 156, 157, 213, 213, 100, 213, 222, - /* 1940 */ 207, 214, 214, 106, 107, 4, 222, 207, 3, 22, - /* 1950 */ 163, 114, 15, 116, 117, 118, 16, 23, 121, 23, - /* 1960 */ 139, 151, 130, 25, 142, 16, 24, 20, 144, 1, - /* 1970 */ 142, 130, 130, 61, 53, 53, 37, 151, 53, 53, - /* 1980 */ 130, 116, 34, 1, 141, 5, 22, 115, 161, 141, - /* 1990 */ 153, 154, 155, 156, 157, 25, 68, 68, 75, 41, - /* 2000 */ 115, 24, 131, 20, 19, 125, 22, 96, 22, 22, - /* 2010 */ 67, 23, 22, 67, 59, 24, 22, 28, 67, 23, - /* 2020 */ 22, 22, 149, 23, 23, 23, 116, 23, 25, 37, - /* 2030 */ 97, 141, 23, 23, 22, 143, 25, 75, 88, 34, - /* 2040 */ 34, 34, 34, 86, 75, 93, 23, 34, 22, 34, - /* 2050 */ 25, 24, 34, 25, 23, 142, 23, 142, 44, 23, - /* 2060 */ 23, 23, 11, 23, 25, 22, 22, 22, 15, 23, - /* 2070 */ 23, 22, 22, 25, 1, 1, 141, 25, 23, 135, - /* 2080 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, - /* 2090 */ 319, 319, 319, 319, 141, 141, 319, 319, 319, 319, + /* 1690 */ 217, 7, 8, 23, 59, 25, 83, 84, 36, 23, + /* 1700 */ 193, 25, 23, 23, 25, 25, 71, 153, 145, 155, + /* 1710 */ 117, 153, 23, 155, 25, 23, 97, 25, 70, 193, + /* 1720 */ 193, 59, 117, 236, 193, 193, 78, 193, 193, 81, + /* 1730 */ 141, 193, 193, 71, 193, 100, 288, 287, 242, 255, + /* 1740 */ 255, 106, 107, 108, 255, 255, 98, 243, 297, 114, + /* 1750 */ 214, 116, 117, 118, 245, 191, 121, 271, 293, 267, + /* 1760 */ 267, 246, 100, 246, 245, 271, 271, 293, 106, 107, + /* 1770 */ 220, 271, 229, 225, 249, 219, 114, 259, 116, 117, + /* 1780 */ 118, 133, 259, 121, 219, 219, 138, 139, 153, 154, + /* 1790 */ 155, 156, 157, 280, 249, 243, 19, 20, 245, 22, + /* 1800 */ 196, 259, 140, 259, 60, 297, 141, 297, 200, 200, + /* 1810 */ 162, 38, 200, 36, 294, 153, 154, 155, 156, 157, + /* 1820 */ 151, 150, 294, 283, 22, 43, 234, 18, 237, 200, + /* 1830 */ 270, 272, 237, 237, 237, 18, 59, 199, 270, 149, + /* 1840 */ 246, 272, 272, 200, 234, 234, 246, 246, 71, 246, + /* 1850 */ 199, 158, 290, 62, 22, 200, 19, 20, 199, 22, + /* 1860 */ 289, 221, 221, 200, 200, 199, 199, 115, 218, 64, + /* 1870 */ 218, 218, 22, 36, 227, 126, 227, 100, 165, 221, + /* 1880 */ 224, 224, 24, 106, 107, 312, 218, 305, 113, 282, + /* 1890 */ 91, 114, 220, 116, 117, 118, 59, 282, 121, 218, + /* 1900 */ 218, 218, 200, 317, 317, 82, 221, 265, 71, 148, + /* 1910 */ 145, 265, 22, 277, 200, 158, 279, 140, 147, 25, + /* 1920 */ 146, 202, 248, 250, 249, 247, 13, 250, 194, 194, + /* 1930 */ 153, 154, 155, 156, 157, 6, 303, 100, 192, 192, + /* 1940 */ 246, 213, 192, 106, 107, 207, 213, 207, 222, 213, + /* 1950 */ 213, 114, 222, 116, 117, 118, 214, 214, 121, 4, + /* 1960 */ 207, 213, 3, 22, 303, 15, 163, 16, 23, 23, + /* 1970 */ 139, 151, 130, 25, 20, 142, 24, 16, 144, 1, + /* 1980 */ 142, 130, 130, 61, 37, 53, 300, 151, 53, 53, + /* 1990 */ 153, 154, 155, 156, 157, 53, 130, 116, 34, 1, + /* 2000 */ 141, 5, 22, 115, 161, 68, 25, 68, 75, 41, + /* 2010 */ 141, 115, 24, 20, 19, 131, 125, 23, 28, 22, + /* 2020 */ 67, 22, 22, 22, 67, 59, 24, 96, 22, 67, + /* 2030 */ 23, 149, 22, 25, 23, 23, 23, 22, 34, 141, + /* 2040 */ 37, 97, 23, 23, 116, 22, 143, 25, 34, 75, + /* 2050 */ 34, 34, 34, 88, 75, 34, 86, 23, 22, 34, + /* 2060 */ 93, 24, 34, 25, 25, 142, 142, 23, 44, 23, + /* 2070 */ 23, 23, 23, 11, 23, 25, 22, 22, 22, 141, + /* 2080 */ 23, 23, 22, 22, 25, 15, 1, 23, 25, 1, + /* 2090 */ 141, 135, 319, 319, 319, 319, 319, 319, 319, 141, /* 2100 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2110 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2120 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, @@ -170254,176 +171415,177 @@ static const YYCODETYPE yy_lookahead[] = { /* 2250 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2260 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2270 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, - /* 2280 */ 319, + /* 2280 */ 319, 319, 319, 319, 319, }; -#define YY_SHIFT_COUNT (574) +#define YY_SHIFT_COUNT (578) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (2074) +#define YY_SHIFT_MAX (2088) static const unsigned short int yy_shift_ofst[] = { /* 0 */ 1648, 1477, 1272, 322, 322, 1, 1319, 1478, 1491, 1837, /* 10 */ 1837, 1837, 471, 0, 0, 214, 1093, 1837, 1837, 1837, /* 20 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, - /* 30 */ 271, 271, 1219, 1219, 216, 88, 1, 1, 1, 1, - /* 40 */ 1, 40, 111, 258, 361, 469, 512, 583, 622, 693, - /* 50 */ 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, 1093, + /* 30 */ 1837, 271, 271, 1219, 1219, 216, 88, 1, 1, 1, + /* 40 */ 1, 1, 40, 111, 258, 361, 469, 512, 583, 622, + /* 50 */ 693, 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, /* 60 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, - /* 70 */ 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1635, 1662, - /* 80 */ 1777, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, + /* 70 */ 1093, 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1635, + /* 80 */ 1662, 1777, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, /* 90 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, /* 100 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, /* 110 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, /* 120 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, - /* 130 */ 137, 181, 181, 181, 181, 181, 181, 181, 94, 430, - /* 140 */ 66, 65, 112, 366, 533, 533, 740, 1261, 533, 533, - /* 150 */ 79, 79, 533, 412, 412, 412, 77, 412, 123, 113, - /* 160 */ 113, 22, 22, 2096, 2096, 328, 328, 328, 239, 468, - /* 170 */ 468, 468, 468, 1015, 1015, 409, 366, 1129, 1186, 533, - /* 180 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533, - /* 190 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 969, - /* 200 */ 621, 621, 533, 642, 788, 788, 1228, 1228, 822, 822, - /* 210 */ 67, 1274, 2096, 2096, 2096, 2096, 2096, 2096, 2096, 1307, - /* 220 */ 954, 954, 585, 472, 640, 387, 695, 538, 541, 700, - /* 230 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533, - /* 240 */ 222, 533, 533, 533, 533, 533, 533, 533, 533, 533, - /* 250 */ 533, 533, 533, 1179, 1179, 1179, 533, 533, 533, 565, - /* 260 */ 533, 533, 533, 916, 1144, 533, 533, 1288, 533, 533, - /* 270 */ 533, 533, 533, 533, 533, 533, 639, 1330, 209, 1076, - /* 280 */ 1076, 1076, 1076, 580, 209, 209, 1313, 768, 917, 649, - /* 290 */ 1181, 1316, 405, 1316, 1238, 249, 1181, 1181, 249, 1181, - /* 300 */ 405, 1238, 1369, 464, 1259, 1012, 1012, 1012, 1368, 1368, - /* 310 */ 1368, 1368, 184, 184, 1326, 904, 1287, 1480, 1712, 1712, - /* 320 */ 1633, 1633, 1757, 1757, 1633, 1647, 1651, 1783, 1764, 1791, - /* 330 */ 1791, 1791, 1791, 1633, 1806, 1677, 1651, 1651, 1677, 1783, - /* 340 */ 1764, 1677, 1764, 1677, 1633, 1806, 1674, 1779, 1633, 1806, - /* 350 */ 1823, 1633, 1806, 1633, 1806, 1823, 1732, 1732, 1732, 1794, - /* 360 */ 1840, 1840, 1823, 1732, 1738, 1732, 1794, 1732, 1732, 1701, - /* 370 */ 1844, 1758, 1758, 1823, 1633, 1789, 1789, 1807, 1807, 1742, - /* 380 */ 1752, 1877, 1633, 1743, 1742, 1759, 1765, 1677, 1879, 1897, - /* 390 */ 1897, 1914, 1914, 1914, 2096, 2096, 2096, 2096, 2096, 2096, - /* 400 */ 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096, 207, - /* 410 */ 1095, 331, 620, 903, 806, 1074, 1483, 1432, 1481, 1322, - /* 420 */ 1370, 1394, 1515, 1291, 1546, 1547, 1557, 1595, 1598, 1599, - /* 430 */ 1434, 1453, 1618, 1462, 1567, 1489, 1644, 1654, 1616, 1660, - /* 440 */ 1548, 1549, 1682, 1685, 1597, 742, 1941, 1945, 1927, 1787, - /* 450 */ 1937, 1940, 1934, 1936, 1821, 1810, 1832, 1938, 1938, 1942, - /* 460 */ 1822, 1947, 1824, 1949, 1968, 1828, 1841, 1938, 1842, 1912, - /* 470 */ 1939, 1938, 1826, 1921, 1922, 1925, 1926, 1850, 1865, 1948, - /* 480 */ 1843, 1982, 1980, 1964, 1872, 1827, 1928, 1970, 1929, 1923, - /* 490 */ 1958, 1848, 1885, 1977, 1983, 1985, 1871, 1880, 1984, 1943, - /* 500 */ 1986, 1987, 1988, 1990, 1946, 1955, 1991, 1911, 1989, 1994, - /* 510 */ 1951, 1992, 1996, 1873, 1998, 2000, 2001, 2002, 2003, 2004, - /* 520 */ 1999, 1933, 1890, 2009, 2010, 1910, 2005, 2012, 1892, 2011, - /* 530 */ 2006, 2007, 2008, 2013, 1950, 1962, 1957, 2014, 1969, 1952, - /* 540 */ 2015, 2023, 2026, 2027, 2025, 2028, 2018, 1913, 1915, 2031, - /* 550 */ 2011, 2033, 2036, 2037, 2038, 2039, 2040, 2043, 2051, 2044, - /* 560 */ 2045, 2046, 2047, 2049, 2050, 2048, 1944, 1935, 1953, 1954, - /* 570 */ 2052, 2055, 2053, 2073, 2074, + /* 130 */ 1837, 137, 181, 181, 181, 181, 181, 181, 181, 94, + /* 140 */ 430, 66, 65, 112, 366, 533, 533, 740, 1257, 533, + /* 150 */ 533, 79, 79, 533, 412, 412, 412, 77, 412, 123, + /* 160 */ 113, 113, 113, 22, 22, 2100, 2100, 328, 328, 328, + /* 170 */ 239, 468, 468, 468, 468, 1015, 1015, 409, 366, 1187, + /* 180 */ 1232, 533, 533, 533, 533, 533, 533, 533, 533, 533, + /* 190 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533, + /* 200 */ 533, 969, 621, 621, 533, 642, 788, 788, 1133, 1133, + /* 210 */ 822, 822, 67, 1193, 2100, 2100, 2100, 2100, 2100, 2100, + /* 220 */ 2100, 1307, 954, 954, 585, 472, 640, 387, 695, 538, + /* 230 */ 541, 700, 533, 533, 533, 533, 533, 533, 533, 533, + /* 240 */ 533, 533, 222, 533, 533, 533, 533, 533, 533, 533, + /* 250 */ 533, 533, 533, 533, 533, 1213, 1213, 1213, 533, 533, + /* 260 */ 533, 565, 533, 533, 533, 916, 1147, 533, 533, 1288, + /* 270 */ 533, 533, 533, 533, 533, 533, 533, 533, 639, 1280, + /* 280 */ 209, 1129, 1129, 1129, 1129, 580, 209, 209, 1209, 768, + /* 290 */ 917, 649, 1315, 1334, 405, 1334, 1383, 249, 1315, 1315, + /* 300 */ 249, 1315, 405, 1383, 1441, 464, 1245, 1417, 1417, 1417, + /* 310 */ 1323, 1323, 1323, 1323, 184, 184, 1335, 1476, 856, 1482, + /* 320 */ 1744, 1744, 1665, 1665, 1773, 1773, 1665, 1669, 1671, 1802, + /* 330 */ 1782, 1809, 1809, 1809, 1809, 1665, 1817, 1690, 1671, 1671, + /* 340 */ 1690, 1802, 1782, 1690, 1782, 1690, 1665, 1817, 1693, 1791, + /* 350 */ 1665, 1817, 1832, 1665, 1817, 1665, 1817, 1832, 1752, 1752, + /* 360 */ 1752, 1805, 1850, 1850, 1832, 1752, 1749, 1752, 1805, 1752, + /* 370 */ 1752, 1713, 1858, 1775, 1775, 1832, 1665, 1799, 1799, 1823, + /* 380 */ 1823, 1761, 1765, 1890, 1665, 1757, 1761, 1771, 1774, 1690, + /* 390 */ 1894, 1913, 1913, 1929, 1929, 1929, 2100, 2100, 2100, 2100, + /* 400 */ 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, + /* 410 */ 2100, 207, 1220, 331, 620, 967, 806, 1074, 1499, 1432, + /* 420 */ 1463, 1479, 1419, 1422, 1557, 1512, 1598, 1599, 1644, 1645, + /* 430 */ 1654, 1660, 1555, 1505, 1684, 1462, 1670, 1563, 1619, 1593, + /* 440 */ 1676, 1679, 1613, 1680, 1554, 1558, 1689, 1692, 1605, 1589, + /* 450 */ 1955, 1959, 1941, 1803, 1950, 1951, 1945, 1946, 1831, 1820, + /* 460 */ 1842, 1948, 1948, 1952, 1833, 1954, 1834, 1961, 1978, 1838, + /* 470 */ 1851, 1948, 1852, 1922, 1947, 1948, 1836, 1932, 1935, 1936, + /* 480 */ 1942, 1866, 1881, 1964, 1859, 1998, 1996, 1980, 1888, 1843, + /* 490 */ 1937, 1981, 1939, 1933, 1968, 1869, 1896, 1988, 1993, 1995, + /* 500 */ 1884, 1891, 1997, 1953, 1999, 2000, 1994, 2001, 1957, 1966, + /* 510 */ 2002, 1931, 1990, 2006, 1962, 2003, 2007, 2004, 1882, 2010, + /* 520 */ 2011, 2012, 2008, 2013, 2015, 1944, 1898, 2019, 2020, 1928, + /* 530 */ 2014, 2023, 1903, 2022, 2016, 2017, 2018, 2021, 1965, 1974, + /* 540 */ 1970, 2024, 1979, 1967, 2025, 2034, 2036, 2037, 2038, 2039, + /* 550 */ 2028, 1923, 1924, 2044, 2022, 2046, 2047, 2048, 2049, 2050, + /* 560 */ 2051, 2054, 2062, 2055, 2056, 2057, 2058, 2060, 2061, 2059, + /* 570 */ 1956, 1938, 1949, 1958, 2063, 2064, 2070, 2085, 2088, }; -#define YY_REDUCE_COUNT (408) +#define YY_REDUCE_COUNT (410) #define YY_REDUCE_MIN (-271) -#define YY_REDUCE_MAX (1740) +#define YY_REDUCE_MAX (1753) static const short yy_reduce_ofst[] = { /* 0 */ -125, 733, 789, 241, 293, -123, -193, -191, -183, -187, /* 10 */ 166, 238, 133, -207, -199, -267, -176, -6, 204, 489, - /* 20 */ 576, -175, 598, 686, 615, 725, 860, 778, 781, 857, - /* 30 */ 616, 887, 87, 240, -192, 408, 626, 796, 843, 854, - /* 40 */ 1003, -271, -271, -271, -271, -271, -271, -271, -271, -271, + /* 20 */ 576, 598, -175, 686, 860, 615, 725, 1014, 778, 781, + /* 30 */ 857, 616, 887, 87, 240, -192, 408, 626, 796, 843, + /* 40 */ 854, 1004, -271, -271, -271, -271, -271, -271, -271, -271, /* 50 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271, /* 60 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271, - /* 70 */ -271, -271, -271, -271, -271, -271, -271, -271, 80, 83, - /* 80 */ 313, 886, 888, 996, 1034, 1059, 1081, 1100, 1117, 1152, - /* 90 */ 1155, 1163, 1165, 1167, 1169, 1172, 1180, 1182, 1184, 1198, - /* 100 */ 1200, 1213, 1215, 1225, 1227, 1252, 1254, 1264, 1299, 1303, - /* 110 */ 1308, 1312, 1325, 1328, 1337, 1340, 1343, 1371, 1373, 1384, - /* 120 */ 1386, 1411, 1420, 1424, 1426, 1458, 1470, 1473, 1475, 1479, - /* 130 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271, - /* 140 */ -271, 138, 459, 396, -158, 470, 302, -212, 521, 201, - /* 150 */ -195, -92, 559, 630, 632, 630, -271, 632, 901, 63, - /* 160 */ 407, -271, -271, -271, -271, 161, 161, 161, 251, 335, - /* 170 */ 847, 960, 980, 537, 588, 618, 628, 688, 688, -166, - /* 180 */ -161, 674, 790, 794, 799, 851, 852, -122, 680, -120, - /* 190 */ 995, 1038, 415, 1051, 893, 798, 962, 400, 1086, 779, - /* 200 */ 923, 924, 263, 1041, 979, 990, 1083, 1097, 1031, 1194, - /* 210 */ 362, 994, 1139, 1005, 1037, 1202, 1205, 1195, 1210, -194, - /* 220 */ 56, 185, -135, 232, 522, 560, 601, 617, 669, 683, - /* 230 */ 711, 856, 908, 941, 1048, 1101, 1147, 1257, 1262, 1265, - /* 240 */ 392, 1292, 1333, 1339, 1342, 1346, 1350, 1359, 1374, 1418, - /* 250 */ 1421, 1436, 1437, 593, 755, 770, 997, 1445, 1459, 1209, - /* 260 */ 1500, 1504, 1516, 1132, 1243, 1518, 1519, 1440, 1520, 560, - /* 270 */ 1522, 1523, 1524, 1526, 1527, 1529, 1382, 1438, 1431, 1468, - /* 280 */ 1469, 1472, 1476, 1209, 1431, 1431, 1485, 1525, 1539, 1435, - /* 290 */ 1463, 1471, 1492, 1487, 1443, 1494, 1474, 1484, 1498, 1486, - /* 300 */ 1502, 1455, 1530, 1531, 1533, 1540, 1542, 1544, 1505, 1506, - /* 310 */ 1507, 1508, 1521, 1528, 1493, 1537, 1532, 1575, 1488, 1496, - /* 320 */ 1584, 1594, 1509, 1510, 1600, 1538, 1534, 1541, 1574, 1577, - /* 330 */ 1583, 1585, 1586, 1612, 1626, 1581, 1556, 1558, 1587, 1559, - /* 340 */ 1601, 1588, 1603, 1592, 1631, 1640, 1550, 1553, 1643, 1645, - /* 350 */ 1625, 1649, 1652, 1650, 1653, 1632, 1636, 1637, 1642, 1634, - /* 360 */ 1639, 1641, 1646, 1656, 1655, 1658, 1659, 1661, 1663, 1560, - /* 370 */ 1564, 1596, 1605, 1664, 1670, 1565, 1571, 1627, 1638, 1657, - /* 380 */ 1665, 1623, 1702, 1630, 1666, 1667, 1671, 1673, 1703, 1718, - /* 390 */ 1719, 1729, 1730, 1731, 1621, 1622, 1628, 1720, 1713, 1716, - /* 400 */ 1722, 1723, 1733, 1717, 1724, 1727, 1728, 1725, 1740, + /* 70 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, 80, + /* 80 */ 83, 313, 886, 888, 918, 938, 1021, 1034, 1036, 1141, + /* 90 */ 1159, 1163, 1166, 1168, 1170, 1176, 1178, 1180, 1184, 1196, + /* 100 */ 1198, 1205, 1215, 1225, 1227, 1236, 1252, 1254, 1264, 1303, + /* 110 */ 1309, 1312, 1322, 1325, 1328, 1337, 1340, 1343, 1353, 1371, + /* 120 */ 1373, 1384, 1386, 1411, 1413, 1420, 1424, 1426, 1458, 1470, + /* 130 */ 1473, -271, -271, -271, -271, -271, -271, -271, -271, -271, + /* 140 */ -271, -271, 138, 459, 396, -158, 470, 302, -212, 521, + /* 150 */ 201, -195, -92, 559, 630, 632, 630, -271, 632, 901, + /* 160 */ 63, 407, 670, -271, -271, -271, -271, 161, 161, 161, + /* 170 */ 251, 335, 847, 979, 1097, 537, 588, 618, 628, 688, + /* 180 */ 688, -166, -161, 674, 787, 794, 799, 852, 996, -122, + /* 190 */ 837, -120, 1018, 1035, 415, 1047, 1001, 958, 1082, 400, + /* 200 */ 1099, 779, 1137, 1142, 263, 1083, 1145, 1150, 1041, 1139, + /* 210 */ 965, 1050, 362, 849, 752, 629, 675, 1162, 1173, 1090, + /* 220 */ 1195, -194, 56, 185, -135, 232, 522, 560, 571, 601, + /* 230 */ 617, 669, 683, 711, 850, 893, 1000, 1040, 1049, 1081, + /* 240 */ 1087, 1101, 392, 1114, 1123, 1155, 1161, 1175, 1271, 1293, + /* 250 */ 1299, 1330, 1339, 1342, 1347, 593, 1282, 1286, 1350, 1359, + /* 260 */ 1368, 1314, 1480, 1483, 1507, 1085, 1338, 1526, 1527, 1487, + /* 270 */ 1531, 560, 1532, 1534, 1535, 1538, 1539, 1541, 1448, 1450, + /* 280 */ 1496, 1484, 1485, 1489, 1490, 1314, 1496, 1496, 1504, 1536, + /* 290 */ 1564, 1451, 1486, 1492, 1509, 1493, 1465, 1515, 1494, 1495, + /* 300 */ 1517, 1500, 1519, 1474, 1550, 1543, 1548, 1556, 1565, 1566, + /* 310 */ 1518, 1523, 1542, 1544, 1525, 1545, 1513, 1553, 1552, 1604, + /* 320 */ 1508, 1510, 1608, 1609, 1520, 1528, 1612, 1540, 1559, 1560, + /* 330 */ 1592, 1591, 1595, 1596, 1597, 1629, 1638, 1594, 1569, 1570, + /* 340 */ 1600, 1568, 1610, 1601, 1611, 1603, 1643, 1651, 1562, 1571, + /* 350 */ 1655, 1659, 1640, 1663, 1666, 1664, 1667, 1641, 1650, 1652, + /* 360 */ 1653, 1647, 1656, 1657, 1658, 1668, 1672, 1681, 1649, 1682, + /* 370 */ 1683, 1573, 1582, 1607, 1615, 1685, 1702, 1586, 1587, 1642, + /* 380 */ 1646, 1673, 1675, 1636, 1714, 1637, 1677, 1674, 1678, 1694, + /* 390 */ 1719, 1734, 1735, 1746, 1747, 1750, 1633, 1661, 1686, 1738, + /* 400 */ 1728, 1733, 1736, 1737, 1740, 1726, 1730, 1742, 1743, 1748, + /* 410 */ 1753, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1639, 1639, 1639, 1469, 1236, 1347, 1236, 1236, 1236, 1469, - /* 10 */ 1469, 1469, 1236, 1377, 1377, 1522, 1269, 1236, 1236, 1236, - /* 20 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1468, 1236, 1236, - /* 30 */ 1236, 1236, 1555, 1555, 1236, 1236, 1236, 1236, 1236, 1236, - /* 40 */ 1236, 1236, 1386, 1236, 1393, 1236, 1236, 1236, 1236, 1236, - /* 50 */ 1470, 1471, 1236, 1236, 1236, 1521, 1523, 1486, 1400, 1399, - /* 60 */ 1398, 1397, 1504, 1365, 1391, 1384, 1388, 1465, 1466, 1464, - /* 70 */ 1617, 1471, 1470, 1236, 1387, 1433, 1449, 1432, 1236, 1236, - /* 80 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 90 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 100 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 110 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 120 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 130 */ 1441, 1448, 1447, 1446, 1455, 1445, 1442, 1435, 1434, 1436, - /* 140 */ 1437, 1236, 1236, 1260, 1236, 1236, 1257, 1311, 1236, 1236, - /* 150 */ 1236, 1236, 1236, 1541, 1540, 1236, 1438, 1236, 1269, 1427, - /* 160 */ 1426, 1452, 1439, 1451, 1450, 1529, 1591, 1590, 1487, 1236, - /* 170 */ 1236, 1236, 1236, 1236, 1236, 1555, 1236, 1236, 1236, 1236, - /* 180 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 190 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1367, - /* 200 */ 1555, 1555, 1236, 1269, 1555, 1555, 1368, 1368, 1265, 1265, - /* 210 */ 1371, 1236, 1536, 1338, 1338, 1338, 1338, 1347, 1338, 1236, - /* 220 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 230 */ 1236, 1236, 1236, 1236, 1526, 1524, 1236, 1236, 1236, 1236, - /* 240 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 250 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 260 */ 1236, 1236, 1236, 1343, 1236, 1236, 1236, 1236, 1236, 1236, - /* 270 */ 1236, 1236, 1236, 1236, 1236, 1584, 1236, 1499, 1325, 1343, - /* 280 */ 1343, 1343, 1343, 1345, 1326, 1324, 1337, 1270, 1243, 1631, - /* 290 */ 1403, 1392, 1344, 1392, 1628, 1390, 1403, 1403, 1390, 1403, - /* 300 */ 1344, 1628, 1286, 1606, 1281, 1377, 1377, 1377, 1367, 1367, - /* 310 */ 1367, 1367, 1371, 1371, 1467, 1344, 1337, 1236, 1631, 1631, - /* 320 */ 1353, 1353, 1630, 1630, 1353, 1487, 1614, 1412, 1314, 1320, - /* 330 */ 1320, 1320, 1320, 1353, 1254, 1390, 1614, 1614, 1390, 1412, - /* 340 */ 1314, 1390, 1314, 1390, 1353, 1254, 1503, 1625, 1353, 1254, - /* 350 */ 1477, 1353, 1254, 1353, 1254, 1477, 1312, 1312, 1312, 1301, - /* 360 */ 1236, 1236, 1477, 1312, 1286, 1312, 1301, 1312, 1312, 1573, - /* 370 */ 1236, 1481, 1481, 1477, 1353, 1565, 1565, 1380, 1380, 1385, - /* 380 */ 1371, 1472, 1353, 1236, 1385, 1383, 1381, 1390, 1304, 1587, - /* 390 */ 1587, 1583, 1583, 1583, 1636, 1636, 1536, 1599, 1269, 1269, - /* 400 */ 1269, 1269, 1599, 1288, 1288, 1270, 1270, 1269, 1599, 1236, - /* 410 */ 1236, 1236, 1236, 1236, 1236, 1594, 1236, 1531, 1488, 1357, - /* 420 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 430 */ 1236, 1236, 1236, 1236, 1542, 1236, 1236, 1236, 1236, 1236, - /* 440 */ 1236, 1236, 1236, 1236, 1236, 1417, 1236, 1239, 1533, 1236, - /* 450 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1394, 1395, 1358, - /* 460 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1409, 1236, 1236, - /* 470 */ 1236, 1404, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 480 */ 1627, 1236, 1236, 1236, 1236, 1236, 1236, 1502, 1501, 1236, - /* 490 */ 1236, 1355, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 500 */ 1236, 1236, 1236, 1236, 1236, 1284, 1236, 1236, 1236, 1236, - /* 510 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 520 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1382, - /* 530 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 540 */ 1236, 1236, 1236, 1236, 1570, 1372, 1236, 1236, 1236, 1236, - /* 550 */ 1618, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, - /* 560 */ 1236, 1236, 1236, 1236, 1236, 1610, 1328, 1418, 1236, 1421, - /* 570 */ 1258, 1236, 1248, 1236, 1236, + /* 0 */ 1648, 1648, 1648, 1478, 1243, 1354, 1243, 1243, 1243, 1478, + /* 10 */ 1478, 1478, 1243, 1384, 1384, 1531, 1276, 1243, 1243, 1243, + /* 20 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1477, 1243, + /* 30 */ 1243, 1243, 1243, 1564, 1564, 1243, 1243, 1243, 1243, 1243, + /* 40 */ 1243, 1243, 1243, 1393, 1243, 1400, 1243, 1243, 1243, 1243, + /* 50 */ 1243, 1479, 1480, 1243, 1243, 1243, 1530, 1532, 1495, 1407, + /* 60 */ 1406, 1405, 1404, 1513, 1372, 1398, 1391, 1395, 1474, 1475, + /* 70 */ 1473, 1626, 1480, 1479, 1243, 1394, 1442, 1458, 1441, 1243, + /* 80 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 90 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 100 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 110 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 120 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 130 */ 1243, 1450, 1457, 1456, 1455, 1464, 1454, 1451, 1444, 1443, + /* 140 */ 1445, 1446, 1243, 1243, 1267, 1243, 1243, 1264, 1318, 1243, + /* 150 */ 1243, 1243, 1243, 1243, 1550, 1549, 1243, 1447, 1243, 1276, + /* 160 */ 1435, 1434, 1433, 1461, 1448, 1460, 1459, 1538, 1600, 1599, + /* 170 */ 1496, 1243, 1243, 1243, 1243, 1243, 1243, 1564, 1243, 1243, + /* 180 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 190 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 200 */ 1243, 1374, 1564, 1564, 1243, 1276, 1564, 1564, 1375, 1375, + /* 210 */ 1272, 1272, 1378, 1243, 1545, 1345, 1345, 1345, 1345, 1354, + /* 220 */ 1345, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 230 */ 1243, 1243, 1243, 1243, 1243, 1243, 1535, 1533, 1243, 1243, + /* 240 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 250 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 260 */ 1243, 1243, 1243, 1243, 1243, 1350, 1243, 1243, 1243, 1243, + /* 270 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1593, 1243, 1508, + /* 280 */ 1332, 1350, 1350, 1350, 1350, 1352, 1333, 1331, 1344, 1277, + /* 290 */ 1250, 1640, 1410, 1399, 1351, 1399, 1637, 1397, 1410, 1410, + /* 300 */ 1397, 1410, 1351, 1637, 1293, 1615, 1288, 1384, 1384, 1384, + /* 310 */ 1374, 1374, 1374, 1374, 1378, 1378, 1476, 1351, 1344, 1243, + /* 320 */ 1640, 1640, 1360, 1360, 1639, 1639, 1360, 1496, 1623, 1419, + /* 330 */ 1321, 1327, 1327, 1327, 1327, 1360, 1261, 1397, 1623, 1623, + /* 340 */ 1397, 1419, 1321, 1397, 1321, 1397, 1360, 1261, 1512, 1634, + /* 350 */ 1360, 1261, 1486, 1360, 1261, 1360, 1261, 1486, 1319, 1319, + /* 360 */ 1319, 1308, 1243, 1243, 1486, 1319, 1293, 1319, 1308, 1319, + /* 370 */ 1319, 1582, 1243, 1490, 1490, 1486, 1360, 1574, 1574, 1387, + /* 380 */ 1387, 1392, 1378, 1481, 1360, 1243, 1392, 1390, 1388, 1397, + /* 390 */ 1311, 1596, 1596, 1592, 1592, 1592, 1645, 1645, 1545, 1608, + /* 400 */ 1276, 1276, 1276, 1276, 1608, 1295, 1295, 1277, 1277, 1276, + /* 410 */ 1608, 1243, 1243, 1243, 1243, 1243, 1243, 1603, 1243, 1540, + /* 420 */ 1497, 1364, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 430 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1551, 1243, + /* 440 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1424, + /* 450 */ 1243, 1246, 1542, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 460 */ 1243, 1401, 1402, 1365, 1243, 1243, 1243, 1243, 1243, 1243, + /* 470 */ 1243, 1416, 1243, 1243, 1243, 1411, 1243, 1243, 1243, 1243, + /* 480 */ 1243, 1243, 1243, 1243, 1636, 1243, 1243, 1243, 1243, 1243, + /* 490 */ 1243, 1511, 1510, 1243, 1243, 1362, 1243, 1243, 1243, 1243, + /* 500 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1291, + /* 510 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 520 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 530 */ 1243, 1243, 1243, 1389, 1243, 1243, 1243, 1243, 1243, 1243, + /* 540 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1579, 1379, + /* 550 */ 1243, 1243, 1243, 1243, 1627, 1243, 1243, 1243, 1243, 1243, + /* 560 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1619, + /* 570 */ 1335, 1425, 1243, 1428, 1265, 1243, 1255, 1243, 1243, }; /********** End of lemon-generated parsing tables *****************************/ @@ -171230,221 +172392,223 @@ static const char *const yyRuleName[] = { /* 185 */ "expr ::= expr COLLATE ID|STRING", /* 186 */ "expr ::= CAST LP expr AS typetoken RP", /* 187 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP", - /* 188 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP", - /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over", - /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over", - /* 191 */ "term ::= CTIME_KW", - /* 192 */ "expr ::= LP nexprlist COMMA expr RP", - /* 193 */ "expr ::= expr AND expr", - /* 194 */ "expr ::= expr OR expr", - /* 195 */ "expr ::= expr LT|GT|GE|LE expr", - /* 196 */ "expr ::= expr EQ|NE expr", - /* 197 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 198 */ "expr ::= expr PLUS|MINUS expr", - /* 199 */ "expr ::= expr STAR|SLASH|REM expr", - /* 200 */ "expr ::= expr CONCAT expr", - /* 201 */ "likeop ::= NOT LIKE_KW|MATCH", - /* 202 */ "expr ::= expr likeop expr", - /* 203 */ "expr ::= expr likeop expr ESCAPE expr", - /* 204 */ "expr ::= expr ISNULL|NOTNULL", - /* 205 */ "expr ::= expr NOT NULL", - /* 206 */ "expr ::= expr IS expr", - /* 207 */ "expr ::= expr IS NOT expr", - /* 208 */ "expr ::= expr IS NOT DISTINCT FROM expr", - /* 209 */ "expr ::= expr IS DISTINCT FROM expr", - /* 210 */ "expr ::= NOT expr", - /* 211 */ "expr ::= BITNOT expr", - /* 212 */ "expr ::= PLUS|MINUS expr", - /* 213 */ "expr ::= expr PTR expr", - /* 214 */ "between_op ::= BETWEEN", - /* 215 */ "between_op ::= NOT BETWEEN", - /* 216 */ "expr ::= expr between_op expr AND expr", - /* 217 */ "in_op ::= IN", - /* 218 */ "in_op ::= NOT IN", - /* 219 */ "expr ::= expr in_op LP exprlist RP", - /* 220 */ "expr ::= LP select RP", - /* 221 */ "expr ::= expr in_op LP select RP", - /* 222 */ "expr ::= expr in_op nm dbnm paren_exprlist", - /* 223 */ "expr ::= EXISTS LP select RP", - /* 224 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 225 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 226 */ "case_exprlist ::= WHEN expr THEN expr", - /* 227 */ "case_else ::= ELSE expr", - /* 228 */ "case_else ::=", - /* 229 */ "case_operand ::=", - /* 230 */ "exprlist ::=", - /* 231 */ "nexprlist ::= nexprlist COMMA expr", - /* 232 */ "nexprlist ::= expr", - /* 233 */ "paren_exprlist ::=", - /* 234 */ "paren_exprlist ::= LP exprlist RP", - /* 235 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 236 */ "uniqueflag ::= UNIQUE", - /* 237 */ "uniqueflag ::=", - /* 238 */ "eidlist_opt ::=", - /* 239 */ "eidlist_opt ::= LP eidlist RP", - /* 240 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 241 */ "eidlist ::= nm collate sortorder", - /* 242 */ "collate ::=", - /* 243 */ "collate ::= COLLATE ID|STRING", - /* 244 */ "cmd ::= DROP INDEX ifexists fullname", - /* 245 */ "cmd ::= VACUUM vinto", - /* 246 */ "cmd ::= VACUUM nm vinto", - /* 247 */ "vinto ::= INTO expr", - /* 248 */ "vinto ::=", - /* 249 */ "cmd ::= PRAGMA nm dbnm", - /* 250 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 251 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 252 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 253 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 254 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 255 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 256 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 257 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 258 */ "trigger_time ::= BEFORE|AFTER", - /* 259 */ "trigger_time ::= INSTEAD OF", - /* 260 */ "trigger_time ::=", - /* 261 */ "trigger_event ::= DELETE|INSERT", - /* 262 */ "trigger_event ::= UPDATE", - /* 263 */ "trigger_event ::= UPDATE OF idlist", - /* 264 */ "when_clause ::=", - /* 265 */ "when_clause ::= WHEN expr", - /* 266 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 267 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 268 */ "trnm ::= nm DOT nm", - /* 269 */ "tridxby ::= INDEXED BY nm", - /* 270 */ "tridxby ::= NOT INDEXED", - /* 271 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", - /* 272 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", - /* 273 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", - /* 274 */ "trigger_cmd ::= scanpt select scanpt", - /* 275 */ "expr ::= RAISE LP IGNORE RP", - /* 276 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 277 */ "raisetype ::= ROLLBACK", - /* 278 */ "raisetype ::= ABORT", - /* 279 */ "raisetype ::= FAIL", - /* 280 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 281 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 282 */ "cmd ::= DETACH database_kw_opt expr", - /* 283 */ "key_opt ::=", - /* 284 */ "key_opt ::= KEY expr", - /* 285 */ "cmd ::= REINDEX", - /* 286 */ "cmd ::= REINDEX nm dbnm", - /* 287 */ "cmd ::= ANALYZE", - /* 288 */ "cmd ::= ANALYZE nm dbnm", - /* 289 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 290 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", - /* 291 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", - /* 292 */ "add_column_fullname ::= fullname", - /* 293 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", - /* 294 */ "cmd ::= create_vtab", - /* 295 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 296 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 297 */ "vtabarg ::=", - /* 298 */ "vtabargtoken ::= ANY", - /* 299 */ "vtabargtoken ::= lp anylist RP", - /* 300 */ "lp ::= LP", - /* 301 */ "with ::= WITH wqlist", - /* 302 */ "with ::= WITH RECURSIVE wqlist", - /* 303 */ "wqas ::= AS", - /* 304 */ "wqas ::= AS MATERIALIZED", - /* 305 */ "wqas ::= AS NOT MATERIALIZED", - /* 306 */ "wqitem ::= nm eidlist_opt wqas LP select RP", - /* 307 */ "wqlist ::= wqitem", - /* 308 */ "wqlist ::= wqlist COMMA wqitem", - /* 309 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", - /* 310 */ "windowdefn ::= nm AS LP window RP", - /* 311 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", - /* 312 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", - /* 313 */ "window ::= ORDER BY sortlist frame_opt", - /* 314 */ "window ::= nm ORDER BY sortlist frame_opt", - /* 315 */ "window ::= nm frame_opt", - /* 316 */ "frame_opt ::=", - /* 317 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", - /* 318 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", - /* 319 */ "range_or_rows ::= RANGE|ROWS|GROUPS", - /* 320 */ "frame_bound_s ::= frame_bound", - /* 321 */ "frame_bound_s ::= UNBOUNDED PRECEDING", - /* 322 */ "frame_bound_e ::= frame_bound", - /* 323 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", - /* 324 */ "frame_bound ::= expr PRECEDING|FOLLOWING", - /* 325 */ "frame_bound ::= CURRENT ROW", - /* 326 */ "frame_exclude_opt ::=", - /* 327 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", - /* 328 */ "frame_exclude ::= NO OTHERS", - /* 329 */ "frame_exclude ::= CURRENT ROW", - /* 330 */ "frame_exclude ::= GROUP|TIES", - /* 331 */ "window_clause ::= WINDOW windowdefn_list", - /* 332 */ "filter_over ::= filter_clause over_clause", - /* 333 */ "filter_over ::= over_clause", - /* 334 */ "filter_over ::= filter_clause", - /* 335 */ "over_clause ::= OVER LP window RP", - /* 336 */ "over_clause ::= OVER nm", - /* 337 */ "filter_clause ::= FILTER LP WHERE expr RP", - /* 338 */ "input ::= cmdlist", - /* 339 */ "cmdlist ::= cmdlist ecmd", - /* 340 */ "cmdlist ::= ecmd", - /* 341 */ "ecmd ::= SEMI", - /* 342 */ "ecmd ::= cmdx SEMI", - /* 343 */ "ecmd ::= explain cmdx SEMI", - /* 344 */ "trans_opt ::=", - /* 345 */ "trans_opt ::= TRANSACTION", - /* 346 */ "trans_opt ::= TRANSACTION nm", - /* 347 */ "savepoint_opt ::= SAVEPOINT", - /* 348 */ "savepoint_opt ::=", - /* 349 */ "cmd ::= create_table create_table_args", - /* 350 */ "table_option_set ::= table_option", - /* 351 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 352 */ "columnlist ::= columnname carglist", - /* 353 */ "nm ::= ID|INDEXED|JOIN_KW", - /* 354 */ "nm ::= STRING", - /* 355 */ "typetoken ::= typename", - /* 356 */ "typename ::= ID|STRING", - /* 357 */ "signed ::= plus_num", - /* 358 */ "signed ::= minus_num", - /* 359 */ "carglist ::= carglist ccons", - /* 360 */ "carglist ::=", - /* 361 */ "ccons ::= NULL onconf", - /* 362 */ "ccons ::= GENERATED ALWAYS AS generated", - /* 363 */ "ccons ::= AS generated", - /* 364 */ "conslist_opt ::= COMMA conslist", - /* 365 */ "conslist ::= conslist tconscomma tcons", - /* 366 */ "conslist ::= tcons", - /* 367 */ "tconscomma ::=", - /* 368 */ "defer_subclause_opt ::= defer_subclause", - /* 369 */ "resolvetype ::= raisetype", - /* 370 */ "selectnowith ::= oneselect", - /* 371 */ "oneselect ::= values", - /* 372 */ "sclp ::= selcollist COMMA", - /* 373 */ "as ::= ID|STRING", - /* 374 */ "indexed_opt ::= indexed_by", - /* 375 */ "returning ::=", - /* 376 */ "expr ::= term", - /* 377 */ "likeop ::= LIKE_KW|MATCH", - /* 378 */ "case_operand ::= expr", - /* 379 */ "exprlist ::= nexprlist", - /* 380 */ "nmnum ::= plus_num", - /* 381 */ "nmnum ::= nm", - /* 382 */ "nmnum ::= ON", - /* 383 */ "nmnum ::= DELETE", - /* 384 */ "nmnum ::= DEFAULT", - /* 385 */ "plus_num ::= INTEGER|FLOAT", - /* 386 */ "foreach_clause ::=", - /* 387 */ "foreach_clause ::= FOR EACH ROW", - /* 388 */ "trnm ::= nm", - /* 389 */ "tridxby ::=", - /* 390 */ "database_kw_opt ::= DATABASE", - /* 391 */ "database_kw_opt ::=", - /* 392 */ "kwcolumn_opt ::=", - /* 393 */ "kwcolumn_opt ::= COLUMNKW", - /* 394 */ "vtabarglist ::= vtabarg", - /* 395 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 396 */ "vtabarg ::= vtabarg vtabargtoken", - /* 397 */ "anylist ::=", - /* 398 */ "anylist ::= anylist LP anylist RP", - /* 399 */ "anylist ::= anylist ANY", - /* 400 */ "with ::=", - /* 401 */ "windowdefn_list ::= windowdefn", - /* 402 */ "window ::= frame_opt", + /* 188 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP", + /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP", + /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over", + /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over", + /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over", + /* 193 */ "term ::= CTIME_KW", + /* 194 */ "expr ::= LP nexprlist COMMA expr RP", + /* 195 */ "expr ::= expr AND expr", + /* 196 */ "expr ::= expr OR expr", + /* 197 */ "expr ::= expr LT|GT|GE|LE expr", + /* 198 */ "expr ::= expr EQ|NE expr", + /* 199 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 200 */ "expr ::= expr PLUS|MINUS expr", + /* 201 */ "expr ::= expr STAR|SLASH|REM expr", + /* 202 */ "expr ::= expr CONCAT expr", + /* 203 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 204 */ "expr ::= expr likeop expr", + /* 205 */ "expr ::= expr likeop expr ESCAPE expr", + /* 206 */ "expr ::= expr ISNULL|NOTNULL", + /* 207 */ "expr ::= expr NOT NULL", + /* 208 */ "expr ::= expr IS expr", + /* 209 */ "expr ::= expr IS NOT expr", + /* 210 */ "expr ::= expr IS NOT DISTINCT FROM expr", + /* 211 */ "expr ::= expr IS DISTINCT FROM expr", + /* 212 */ "expr ::= NOT expr", + /* 213 */ "expr ::= BITNOT expr", + /* 214 */ "expr ::= PLUS|MINUS expr", + /* 215 */ "expr ::= expr PTR expr", + /* 216 */ "between_op ::= BETWEEN", + /* 217 */ "between_op ::= NOT BETWEEN", + /* 218 */ "expr ::= expr between_op expr AND expr", + /* 219 */ "in_op ::= IN", + /* 220 */ "in_op ::= NOT IN", + /* 221 */ "expr ::= expr in_op LP exprlist RP", + /* 222 */ "expr ::= LP select RP", + /* 223 */ "expr ::= expr in_op LP select RP", + /* 224 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 225 */ "expr ::= EXISTS LP select RP", + /* 226 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 227 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 228 */ "case_exprlist ::= WHEN expr THEN expr", + /* 229 */ "case_else ::= ELSE expr", + /* 230 */ "case_else ::=", + /* 231 */ "case_operand ::=", + /* 232 */ "exprlist ::=", + /* 233 */ "nexprlist ::= nexprlist COMMA expr", + /* 234 */ "nexprlist ::= expr", + /* 235 */ "paren_exprlist ::=", + /* 236 */ "paren_exprlist ::= LP exprlist RP", + /* 237 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 238 */ "uniqueflag ::= UNIQUE", + /* 239 */ "uniqueflag ::=", + /* 240 */ "eidlist_opt ::=", + /* 241 */ "eidlist_opt ::= LP eidlist RP", + /* 242 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 243 */ "eidlist ::= nm collate sortorder", + /* 244 */ "collate ::=", + /* 245 */ "collate ::= COLLATE ID|STRING", + /* 246 */ "cmd ::= DROP INDEX ifexists fullname", + /* 247 */ "cmd ::= VACUUM vinto", + /* 248 */ "cmd ::= VACUUM nm vinto", + /* 249 */ "vinto ::= INTO expr", + /* 250 */ "vinto ::=", + /* 251 */ "cmd ::= PRAGMA nm dbnm", + /* 252 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 253 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 254 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 255 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 256 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 257 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 258 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 259 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 260 */ "trigger_time ::= BEFORE|AFTER", + /* 261 */ "trigger_time ::= INSTEAD OF", + /* 262 */ "trigger_time ::=", + /* 263 */ "trigger_event ::= DELETE|INSERT", + /* 264 */ "trigger_event ::= UPDATE", + /* 265 */ "trigger_event ::= UPDATE OF idlist", + /* 266 */ "when_clause ::=", + /* 267 */ "when_clause ::= WHEN expr", + /* 268 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 269 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 270 */ "trnm ::= nm DOT nm", + /* 271 */ "tridxby ::= INDEXED BY nm", + /* 272 */ "tridxby ::= NOT INDEXED", + /* 273 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", + /* 274 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", + /* 275 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", + /* 276 */ "trigger_cmd ::= scanpt select scanpt", + /* 277 */ "expr ::= RAISE LP IGNORE RP", + /* 278 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 279 */ "raisetype ::= ROLLBACK", + /* 280 */ "raisetype ::= ABORT", + /* 281 */ "raisetype ::= FAIL", + /* 282 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 283 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 284 */ "cmd ::= DETACH database_kw_opt expr", + /* 285 */ "key_opt ::=", + /* 286 */ "key_opt ::= KEY expr", + /* 287 */ "cmd ::= REINDEX", + /* 288 */ "cmd ::= REINDEX nm dbnm", + /* 289 */ "cmd ::= ANALYZE", + /* 290 */ "cmd ::= ANALYZE nm dbnm", + /* 291 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 292 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 293 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", + /* 294 */ "add_column_fullname ::= fullname", + /* 295 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", + /* 296 */ "cmd ::= create_vtab", + /* 297 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 298 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 299 */ "vtabarg ::=", + /* 300 */ "vtabargtoken ::= ANY", + /* 301 */ "vtabargtoken ::= lp anylist RP", + /* 302 */ "lp ::= LP", + /* 303 */ "with ::= WITH wqlist", + /* 304 */ "with ::= WITH RECURSIVE wqlist", + /* 305 */ "wqas ::= AS", + /* 306 */ "wqas ::= AS MATERIALIZED", + /* 307 */ "wqas ::= AS NOT MATERIALIZED", + /* 308 */ "wqitem ::= nm eidlist_opt wqas LP select RP", + /* 309 */ "wqlist ::= wqitem", + /* 310 */ "wqlist ::= wqlist COMMA wqitem", + /* 311 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", + /* 312 */ "windowdefn ::= nm AS LP window RP", + /* 313 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", + /* 314 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", + /* 315 */ "window ::= ORDER BY sortlist frame_opt", + /* 316 */ "window ::= nm ORDER BY sortlist frame_opt", + /* 317 */ "window ::= nm frame_opt", + /* 318 */ "frame_opt ::=", + /* 319 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", + /* 320 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", + /* 321 */ "range_or_rows ::= RANGE|ROWS|GROUPS", + /* 322 */ "frame_bound_s ::= frame_bound", + /* 323 */ "frame_bound_s ::= UNBOUNDED PRECEDING", + /* 324 */ "frame_bound_e ::= frame_bound", + /* 325 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", + /* 326 */ "frame_bound ::= expr PRECEDING|FOLLOWING", + /* 327 */ "frame_bound ::= CURRENT ROW", + /* 328 */ "frame_exclude_opt ::=", + /* 329 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", + /* 330 */ "frame_exclude ::= NO OTHERS", + /* 331 */ "frame_exclude ::= CURRENT ROW", + /* 332 */ "frame_exclude ::= GROUP|TIES", + /* 333 */ "window_clause ::= WINDOW windowdefn_list", + /* 334 */ "filter_over ::= filter_clause over_clause", + /* 335 */ "filter_over ::= over_clause", + /* 336 */ "filter_over ::= filter_clause", + /* 337 */ "over_clause ::= OVER LP window RP", + /* 338 */ "over_clause ::= OVER nm", + /* 339 */ "filter_clause ::= FILTER LP WHERE expr RP", + /* 340 */ "input ::= cmdlist", + /* 341 */ "cmdlist ::= cmdlist ecmd", + /* 342 */ "cmdlist ::= ecmd", + /* 343 */ "ecmd ::= SEMI", + /* 344 */ "ecmd ::= cmdx SEMI", + /* 345 */ "ecmd ::= explain cmdx SEMI", + /* 346 */ "trans_opt ::=", + /* 347 */ "trans_opt ::= TRANSACTION", + /* 348 */ "trans_opt ::= TRANSACTION nm", + /* 349 */ "savepoint_opt ::= SAVEPOINT", + /* 350 */ "savepoint_opt ::=", + /* 351 */ "cmd ::= create_table create_table_args", + /* 352 */ "table_option_set ::= table_option", + /* 353 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 354 */ "columnlist ::= columnname carglist", + /* 355 */ "nm ::= ID|INDEXED|JOIN_KW", + /* 356 */ "nm ::= STRING", + /* 357 */ "typetoken ::= typename", + /* 358 */ "typename ::= ID|STRING", + /* 359 */ "signed ::= plus_num", + /* 360 */ "signed ::= minus_num", + /* 361 */ "carglist ::= carglist ccons", + /* 362 */ "carglist ::=", + /* 363 */ "ccons ::= NULL onconf", + /* 364 */ "ccons ::= GENERATED ALWAYS AS generated", + /* 365 */ "ccons ::= AS generated", + /* 366 */ "conslist_opt ::= COMMA conslist", + /* 367 */ "conslist ::= conslist tconscomma tcons", + /* 368 */ "conslist ::= tcons", + /* 369 */ "tconscomma ::=", + /* 370 */ "defer_subclause_opt ::= defer_subclause", + /* 371 */ "resolvetype ::= raisetype", + /* 372 */ "selectnowith ::= oneselect", + /* 373 */ "oneselect ::= values", + /* 374 */ "sclp ::= selcollist COMMA", + /* 375 */ "as ::= ID|STRING", + /* 376 */ "indexed_opt ::= indexed_by", + /* 377 */ "returning ::=", + /* 378 */ "expr ::= term", + /* 379 */ "likeop ::= LIKE_KW|MATCH", + /* 380 */ "case_operand ::= expr", + /* 381 */ "exprlist ::= nexprlist", + /* 382 */ "nmnum ::= plus_num", + /* 383 */ "nmnum ::= nm", + /* 384 */ "nmnum ::= ON", + /* 385 */ "nmnum ::= DELETE", + /* 386 */ "nmnum ::= DEFAULT", + /* 387 */ "plus_num ::= INTEGER|FLOAT", + /* 388 */ "foreach_clause ::=", + /* 389 */ "foreach_clause ::= FOR EACH ROW", + /* 390 */ "trnm ::= nm", + /* 391 */ "tridxby ::=", + /* 392 */ "database_kw_opt ::= DATABASE", + /* 393 */ "database_kw_opt ::=", + /* 394 */ "kwcolumn_opt ::=", + /* 395 */ "kwcolumn_opt ::= COLUMNKW", + /* 396 */ "vtabarglist ::= vtabarg", + /* 397 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 398 */ "vtabarg ::= vtabarg vtabargtoken", + /* 399 */ "anylist ::=", + /* 400 */ "anylist ::= anylist LP anylist RP", + /* 401 */ "anylist ::= anylist ANY", + /* 402 */ "with ::=", + /* 403 */ "windowdefn_list ::= windowdefn", + /* 404 */ "window ::= frame_opt", }; #endif /* NDEBUG */ @@ -172139,221 +173303,223 @@ static const YYCODETYPE yyRuleInfoLhs[] = { 217, /* (185) expr ::= expr COLLATE ID|STRING */ 217, /* (186) expr ::= CAST LP expr AS typetoken RP */ 217, /* (187) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ - 217, /* (188) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ - 217, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ - 217, /* (190) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ - 216, /* (191) term ::= CTIME_KW */ - 217, /* (192) expr ::= LP nexprlist COMMA expr RP */ - 217, /* (193) expr ::= expr AND expr */ - 217, /* (194) expr ::= expr OR expr */ - 217, /* (195) expr ::= expr LT|GT|GE|LE expr */ - 217, /* (196) expr ::= expr EQ|NE expr */ - 217, /* (197) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - 217, /* (198) expr ::= expr PLUS|MINUS expr */ - 217, /* (199) expr ::= expr STAR|SLASH|REM expr */ - 217, /* (200) expr ::= expr CONCAT expr */ - 274, /* (201) likeop ::= NOT LIKE_KW|MATCH */ - 217, /* (202) expr ::= expr likeop expr */ - 217, /* (203) expr ::= expr likeop expr ESCAPE expr */ - 217, /* (204) expr ::= expr ISNULL|NOTNULL */ - 217, /* (205) expr ::= expr NOT NULL */ - 217, /* (206) expr ::= expr IS expr */ - 217, /* (207) expr ::= expr IS NOT expr */ - 217, /* (208) expr ::= expr IS NOT DISTINCT FROM expr */ - 217, /* (209) expr ::= expr IS DISTINCT FROM expr */ - 217, /* (210) expr ::= NOT expr */ - 217, /* (211) expr ::= BITNOT expr */ - 217, /* (212) expr ::= PLUS|MINUS expr */ - 217, /* (213) expr ::= expr PTR expr */ - 275, /* (214) between_op ::= BETWEEN */ - 275, /* (215) between_op ::= NOT BETWEEN */ - 217, /* (216) expr ::= expr between_op expr AND expr */ - 276, /* (217) in_op ::= IN */ - 276, /* (218) in_op ::= NOT IN */ - 217, /* (219) expr ::= expr in_op LP exprlist RP */ - 217, /* (220) expr ::= LP select RP */ - 217, /* (221) expr ::= expr in_op LP select RP */ - 217, /* (222) expr ::= expr in_op nm dbnm paren_exprlist */ - 217, /* (223) expr ::= EXISTS LP select RP */ - 217, /* (224) expr ::= CASE case_operand case_exprlist case_else END */ - 279, /* (225) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - 279, /* (226) case_exprlist ::= WHEN expr THEN expr */ - 280, /* (227) case_else ::= ELSE expr */ - 280, /* (228) case_else ::= */ - 278, /* (229) case_operand ::= */ - 261, /* (230) exprlist ::= */ - 253, /* (231) nexprlist ::= nexprlist COMMA expr */ - 253, /* (232) nexprlist ::= expr */ - 277, /* (233) paren_exprlist ::= */ - 277, /* (234) paren_exprlist ::= LP exprlist RP */ - 190, /* (235) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - 281, /* (236) uniqueflag ::= UNIQUE */ - 281, /* (237) uniqueflag ::= */ - 221, /* (238) eidlist_opt ::= */ - 221, /* (239) eidlist_opt ::= LP eidlist RP */ - 232, /* (240) eidlist ::= eidlist COMMA nm collate sortorder */ - 232, /* (241) eidlist ::= nm collate sortorder */ - 282, /* (242) collate ::= */ - 282, /* (243) collate ::= COLLATE ID|STRING */ - 190, /* (244) cmd ::= DROP INDEX ifexists fullname */ - 190, /* (245) cmd ::= VACUUM vinto */ - 190, /* (246) cmd ::= VACUUM nm vinto */ - 283, /* (247) vinto ::= INTO expr */ - 283, /* (248) vinto ::= */ - 190, /* (249) cmd ::= PRAGMA nm dbnm */ - 190, /* (250) cmd ::= PRAGMA nm dbnm EQ nmnum */ - 190, /* (251) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - 190, /* (252) cmd ::= PRAGMA nm dbnm EQ minus_num */ - 190, /* (253) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - 211, /* (254) plus_num ::= PLUS INTEGER|FLOAT */ - 212, /* (255) minus_num ::= MINUS INTEGER|FLOAT */ - 190, /* (256) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - 285, /* (257) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - 287, /* (258) trigger_time ::= BEFORE|AFTER */ - 287, /* (259) trigger_time ::= INSTEAD OF */ - 287, /* (260) trigger_time ::= */ - 288, /* (261) trigger_event ::= DELETE|INSERT */ - 288, /* (262) trigger_event ::= UPDATE */ - 288, /* (263) trigger_event ::= UPDATE OF idlist */ - 290, /* (264) when_clause ::= */ - 290, /* (265) when_clause ::= WHEN expr */ - 286, /* (266) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - 286, /* (267) trigger_cmd_list ::= trigger_cmd SEMI */ - 292, /* (268) trnm ::= nm DOT nm */ - 293, /* (269) tridxby ::= INDEXED BY nm */ - 293, /* (270) tridxby ::= NOT INDEXED */ - 291, /* (271) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - 291, /* (272) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - 291, /* (273) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - 291, /* (274) trigger_cmd ::= scanpt select scanpt */ - 217, /* (275) expr ::= RAISE LP IGNORE RP */ - 217, /* (276) expr ::= RAISE LP raisetype COMMA nm RP */ - 236, /* (277) raisetype ::= ROLLBACK */ - 236, /* (278) raisetype ::= ABORT */ - 236, /* (279) raisetype ::= FAIL */ - 190, /* (280) cmd ::= DROP TRIGGER ifexists fullname */ - 190, /* (281) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - 190, /* (282) cmd ::= DETACH database_kw_opt expr */ - 295, /* (283) key_opt ::= */ - 295, /* (284) key_opt ::= KEY expr */ - 190, /* (285) cmd ::= REINDEX */ - 190, /* (286) cmd ::= REINDEX nm dbnm */ - 190, /* (287) cmd ::= ANALYZE */ - 190, /* (288) cmd ::= ANALYZE nm dbnm */ - 190, /* (289) cmd ::= ALTER TABLE fullname RENAME TO nm */ - 190, /* (290) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - 190, /* (291) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - 296, /* (292) add_column_fullname ::= fullname */ - 190, /* (293) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - 190, /* (294) cmd ::= create_vtab */ - 190, /* (295) cmd ::= create_vtab LP vtabarglist RP */ - 298, /* (296) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 300, /* (297) vtabarg ::= */ - 301, /* (298) vtabargtoken ::= ANY */ - 301, /* (299) vtabargtoken ::= lp anylist RP */ - 302, /* (300) lp ::= LP */ - 266, /* (301) with ::= WITH wqlist */ - 266, /* (302) with ::= WITH RECURSIVE wqlist */ - 305, /* (303) wqas ::= AS */ - 305, /* (304) wqas ::= AS MATERIALIZED */ - 305, /* (305) wqas ::= AS NOT MATERIALIZED */ - 304, /* (306) wqitem ::= nm eidlist_opt wqas LP select RP */ - 241, /* (307) wqlist ::= wqitem */ - 241, /* (308) wqlist ::= wqlist COMMA wqitem */ - 306, /* (309) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - 307, /* (310) windowdefn ::= nm AS LP window RP */ - 308, /* (311) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - 308, /* (312) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - 308, /* (313) window ::= ORDER BY sortlist frame_opt */ - 308, /* (314) window ::= nm ORDER BY sortlist frame_opt */ - 308, /* (315) window ::= nm frame_opt */ - 309, /* (316) frame_opt ::= */ - 309, /* (317) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - 309, /* (318) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - 313, /* (319) range_or_rows ::= RANGE|ROWS|GROUPS */ - 315, /* (320) frame_bound_s ::= frame_bound */ - 315, /* (321) frame_bound_s ::= UNBOUNDED PRECEDING */ - 316, /* (322) frame_bound_e ::= frame_bound */ - 316, /* (323) frame_bound_e ::= UNBOUNDED FOLLOWING */ - 314, /* (324) frame_bound ::= expr PRECEDING|FOLLOWING */ - 314, /* (325) frame_bound ::= CURRENT ROW */ - 317, /* (326) frame_exclude_opt ::= */ - 317, /* (327) frame_exclude_opt ::= EXCLUDE frame_exclude */ - 318, /* (328) frame_exclude ::= NO OTHERS */ - 318, /* (329) frame_exclude ::= CURRENT ROW */ - 318, /* (330) frame_exclude ::= GROUP|TIES */ - 251, /* (331) window_clause ::= WINDOW windowdefn_list */ - 273, /* (332) filter_over ::= filter_clause over_clause */ - 273, /* (333) filter_over ::= over_clause */ - 273, /* (334) filter_over ::= filter_clause */ - 312, /* (335) over_clause ::= OVER LP window RP */ - 312, /* (336) over_clause ::= OVER nm */ - 311, /* (337) filter_clause ::= FILTER LP WHERE expr RP */ - 185, /* (338) input ::= cmdlist */ - 186, /* (339) cmdlist ::= cmdlist ecmd */ - 186, /* (340) cmdlist ::= ecmd */ - 187, /* (341) ecmd ::= SEMI */ - 187, /* (342) ecmd ::= cmdx SEMI */ - 187, /* (343) ecmd ::= explain cmdx SEMI */ - 192, /* (344) trans_opt ::= */ - 192, /* (345) trans_opt ::= TRANSACTION */ - 192, /* (346) trans_opt ::= TRANSACTION nm */ - 194, /* (347) savepoint_opt ::= SAVEPOINT */ - 194, /* (348) savepoint_opt ::= */ - 190, /* (349) cmd ::= create_table create_table_args */ - 203, /* (350) table_option_set ::= table_option */ - 201, /* (351) columnlist ::= columnlist COMMA columnname carglist */ - 201, /* (352) columnlist ::= columnname carglist */ - 193, /* (353) nm ::= ID|INDEXED|JOIN_KW */ - 193, /* (354) nm ::= STRING */ - 208, /* (355) typetoken ::= typename */ - 209, /* (356) typename ::= ID|STRING */ - 210, /* (357) signed ::= plus_num */ - 210, /* (358) signed ::= minus_num */ - 207, /* (359) carglist ::= carglist ccons */ - 207, /* (360) carglist ::= */ - 215, /* (361) ccons ::= NULL onconf */ - 215, /* (362) ccons ::= GENERATED ALWAYS AS generated */ - 215, /* (363) ccons ::= AS generated */ - 202, /* (364) conslist_opt ::= COMMA conslist */ - 228, /* (365) conslist ::= conslist tconscomma tcons */ - 228, /* (366) conslist ::= tcons */ - 229, /* (367) tconscomma ::= */ - 233, /* (368) defer_subclause_opt ::= defer_subclause */ - 235, /* (369) resolvetype ::= raisetype */ - 239, /* (370) selectnowith ::= oneselect */ - 240, /* (371) oneselect ::= values */ - 254, /* (372) sclp ::= selcollist COMMA */ - 255, /* (373) as ::= ID|STRING */ - 264, /* (374) indexed_opt ::= indexed_by */ - 272, /* (375) returning ::= */ - 217, /* (376) expr ::= term */ - 274, /* (377) likeop ::= LIKE_KW|MATCH */ - 278, /* (378) case_operand ::= expr */ - 261, /* (379) exprlist ::= nexprlist */ - 284, /* (380) nmnum ::= plus_num */ - 284, /* (381) nmnum ::= nm */ - 284, /* (382) nmnum ::= ON */ - 284, /* (383) nmnum ::= DELETE */ - 284, /* (384) nmnum ::= DEFAULT */ - 211, /* (385) plus_num ::= INTEGER|FLOAT */ - 289, /* (386) foreach_clause ::= */ - 289, /* (387) foreach_clause ::= FOR EACH ROW */ - 292, /* (388) trnm ::= nm */ - 293, /* (389) tridxby ::= */ - 294, /* (390) database_kw_opt ::= DATABASE */ - 294, /* (391) database_kw_opt ::= */ - 297, /* (392) kwcolumn_opt ::= */ - 297, /* (393) kwcolumn_opt ::= COLUMNKW */ - 299, /* (394) vtabarglist ::= vtabarg */ - 299, /* (395) vtabarglist ::= vtabarglist COMMA vtabarg */ - 300, /* (396) vtabarg ::= vtabarg vtabargtoken */ - 303, /* (397) anylist ::= */ - 303, /* (398) anylist ::= anylist LP anylist RP */ - 303, /* (399) anylist ::= anylist ANY */ - 266, /* (400) with ::= */ - 306, /* (401) windowdefn_list ::= windowdefn */ - 308, /* (402) window ::= frame_opt */ + 217, /* (188) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + 217, /* (189) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + 217, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + 217, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + 217, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + 216, /* (193) term ::= CTIME_KW */ + 217, /* (194) expr ::= LP nexprlist COMMA expr RP */ + 217, /* (195) expr ::= expr AND expr */ + 217, /* (196) expr ::= expr OR expr */ + 217, /* (197) expr ::= expr LT|GT|GE|LE expr */ + 217, /* (198) expr ::= expr EQ|NE expr */ + 217, /* (199) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + 217, /* (200) expr ::= expr PLUS|MINUS expr */ + 217, /* (201) expr ::= expr STAR|SLASH|REM expr */ + 217, /* (202) expr ::= expr CONCAT expr */ + 274, /* (203) likeop ::= NOT LIKE_KW|MATCH */ + 217, /* (204) expr ::= expr likeop expr */ + 217, /* (205) expr ::= expr likeop expr ESCAPE expr */ + 217, /* (206) expr ::= expr ISNULL|NOTNULL */ + 217, /* (207) expr ::= expr NOT NULL */ + 217, /* (208) expr ::= expr IS expr */ + 217, /* (209) expr ::= expr IS NOT expr */ + 217, /* (210) expr ::= expr IS NOT DISTINCT FROM expr */ + 217, /* (211) expr ::= expr IS DISTINCT FROM expr */ + 217, /* (212) expr ::= NOT expr */ + 217, /* (213) expr ::= BITNOT expr */ + 217, /* (214) expr ::= PLUS|MINUS expr */ + 217, /* (215) expr ::= expr PTR expr */ + 275, /* (216) between_op ::= BETWEEN */ + 275, /* (217) between_op ::= NOT BETWEEN */ + 217, /* (218) expr ::= expr between_op expr AND expr */ + 276, /* (219) in_op ::= IN */ + 276, /* (220) in_op ::= NOT IN */ + 217, /* (221) expr ::= expr in_op LP exprlist RP */ + 217, /* (222) expr ::= LP select RP */ + 217, /* (223) expr ::= expr in_op LP select RP */ + 217, /* (224) expr ::= expr in_op nm dbnm paren_exprlist */ + 217, /* (225) expr ::= EXISTS LP select RP */ + 217, /* (226) expr ::= CASE case_operand case_exprlist case_else END */ + 279, /* (227) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + 279, /* (228) case_exprlist ::= WHEN expr THEN expr */ + 280, /* (229) case_else ::= ELSE expr */ + 280, /* (230) case_else ::= */ + 278, /* (231) case_operand ::= */ + 261, /* (232) exprlist ::= */ + 253, /* (233) nexprlist ::= nexprlist COMMA expr */ + 253, /* (234) nexprlist ::= expr */ + 277, /* (235) paren_exprlist ::= */ + 277, /* (236) paren_exprlist ::= LP exprlist RP */ + 190, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + 281, /* (238) uniqueflag ::= UNIQUE */ + 281, /* (239) uniqueflag ::= */ + 221, /* (240) eidlist_opt ::= */ + 221, /* (241) eidlist_opt ::= LP eidlist RP */ + 232, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */ + 232, /* (243) eidlist ::= nm collate sortorder */ + 282, /* (244) collate ::= */ + 282, /* (245) collate ::= COLLATE ID|STRING */ + 190, /* (246) cmd ::= DROP INDEX ifexists fullname */ + 190, /* (247) cmd ::= VACUUM vinto */ + 190, /* (248) cmd ::= VACUUM nm vinto */ + 283, /* (249) vinto ::= INTO expr */ + 283, /* (250) vinto ::= */ + 190, /* (251) cmd ::= PRAGMA nm dbnm */ + 190, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */ + 190, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + 190, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */ + 190, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + 211, /* (256) plus_num ::= PLUS INTEGER|FLOAT */ + 212, /* (257) minus_num ::= MINUS INTEGER|FLOAT */ + 190, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + 285, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + 287, /* (260) trigger_time ::= BEFORE|AFTER */ + 287, /* (261) trigger_time ::= INSTEAD OF */ + 287, /* (262) trigger_time ::= */ + 288, /* (263) trigger_event ::= DELETE|INSERT */ + 288, /* (264) trigger_event ::= UPDATE */ + 288, /* (265) trigger_event ::= UPDATE OF idlist */ + 290, /* (266) when_clause ::= */ + 290, /* (267) when_clause ::= WHEN expr */ + 286, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + 286, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */ + 292, /* (270) trnm ::= nm DOT nm */ + 293, /* (271) tridxby ::= INDEXED BY nm */ + 293, /* (272) tridxby ::= NOT INDEXED */ + 291, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + 291, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + 291, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + 291, /* (276) trigger_cmd ::= scanpt select scanpt */ + 217, /* (277) expr ::= RAISE LP IGNORE RP */ + 217, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */ + 236, /* (279) raisetype ::= ROLLBACK */ + 236, /* (280) raisetype ::= ABORT */ + 236, /* (281) raisetype ::= FAIL */ + 190, /* (282) cmd ::= DROP TRIGGER ifexists fullname */ + 190, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + 190, /* (284) cmd ::= DETACH database_kw_opt expr */ + 295, /* (285) key_opt ::= */ + 295, /* (286) key_opt ::= KEY expr */ + 190, /* (287) cmd ::= REINDEX */ + 190, /* (288) cmd ::= REINDEX nm dbnm */ + 190, /* (289) cmd ::= ANALYZE */ + 190, /* (290) cmd ::= ANALYZE nm dbnm */ + 190, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */ + 190, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + 190, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + 296, /* (294) add_column_fullname ::= fullname */ + 190, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + 190, /* (296) cmd ::= create_vtab */ + 190, /* (297) cmd ::= create_vtab LP vtabarglist RP */ + 298, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 300, /* (299) vtabarg ::= */ + 301, /* (300) vtabargtoken ::= ANY */ + 301, /* (301) vtabargtoken ::= lp anylist RP */ + 302, /* (302) lp ::= LP */ + 266, /* (303) with ::= WITH wqlist */ + 266, /* (304) with ::= WITH RECURSIVE wqlist */ + 305, /* (305) wqas ::= AS */ + 305, /* (306) wqas ::= AS MATERIALIZED */ + 305, /* (307) wqas ::= AS NOT MATERIALIZED */ + 304, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */ + 241, /* (309) wqlist ::= wqitem */ + 241, /* (310) wqlist ::= wqlist COMMA wqitem */ + 306, /* (311) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + 307, /* (312) windowdefn ::= nm AS LP window RP */ + 308, /* (313) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + 308, /* (314) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + 308, /* (315) window ::= ORDER BY sortlist frame_opt */ + 308, /* (316) window ::= nm ORDER BY sortlist frame_opt */ + 308, /* (317) window ::= nm frame_opt */ + 309, /* (318) frame_opt ::= */ + 309, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + 309, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + 313, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */ + 315, /* (322) frame_bound_s ::= frame_bound */ + 315, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */ + 316, /* (324) frame_bound_e ::= frame_bound */ + 316, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */ + 314, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */ + 314, /* (327) frame_bound ::= CURRENT ROW */ + 317, /* (328) frame_exclude_opt ::= */ + 317, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */ + 318, /* (330) frame_exclude ::= NO OTHERS */ + 318, /* (331) frame_exclude ::= CURRENT ROW */ + 318, /* (332) frame_exclude ::= GROUP|TIES */ + 251, /* (333) window_clause ::= WINDOW windowdefn_list */ + 273, /* (334) filter_over ::= filter_clause over_clause */ + 273, /* (335) filter_over ::= over_clause */ + 273, /* (336) filter_over ::= filter_clause */ + 312, /* (337) over_clause ::= OVER LP window RP */ + 312, /* (338) over_clause ::= OVER nm */ + 311, /* (339) filter_clause ::= FILTER LP WHERE expr RP */ + 185, /* (340) input ::= cmdlist */ + 186, /* (341) cmdlist ::= cmdlist ecmd */ + 186, /* (342) cmdlist ::= ecmd */ + 187, /* (343) ecmd ::= SEMI */ + 187, /* (344) ecmd ::= cmdx SEMI */ + 187, /* (345) ecmd ::= explain cmdx SEMI */ + 192, /* (346) trans_opt ::= */ + 192, /* (347) trans_opt ::= TRANSACTION */ + 192, /* (348) trans_opt ::= TRANSACTION nm */ + 194, /* (349) savepoint_opt ::= SAVEPOINT */ + 194, /* (350) savepoint_opt ::= */ + 190, /* (351) cmd ::= create_table create_table_args */ + 203, /* (352) table_option_set ::= table_option */ + 201, /* (353) columnlist ::= columnlist COMMA columnname carglist */ + 201, /* (354) columnlist ::= columnname carglist */ + 193, /* (355) nm ::= ID|INDEXED|JOIN_KW */ + 193, /* (356) nm ::= STRING */ + 208, /* (357) typetoken ::= typename */ + 209, /* (358) typename ::= ID|STRING */ + 210, /* (359) signed ::= plus_num */ + 210, /* (360) signed ::= minus_num */ + 207, /* (361) carglist ::= carglist ccons */ + 207, /* (362) carglist ::= */ + 215, /* (363) ccons ::= NULL onconf */ + 215, /* (364) ccons ::= GENERATED ALWAYS AS generated */ + 215, /* (365) ccons ::= AS generated */ + 202, /* (366) conslist_opt ::= COMMA conslist */ + 228, /* (367) conslist ::= conslist tconscomma tcons */ + 228, /* (368) conslist ::= tcons */ + 229, /* (369) tconscomma ::= */ + 233, /* (370) defer_subclause_opt ::= defer_subclause */ + 235, /* (371) resolvetype ::= raisetype */ + 239, /* (372) selectnowith ::= oneselect */ + 240, /* (373) oneselect ::= values */ + 254, /* (374) sclp ::= selcollist COMMA */ + 255, /* (375) as ::= ID|STRING */ + 264, /* (376) indexed_opt ::= indexed_by */ + 272, /* (377) returning ::= */ + 217, /* (378) expr ::= term */ + 274, /* (379) likeop ::= LIKE_KW|MATCH */ + 278, /* (380) case_operand ::= expr */ + 261, /* (381) exprlist ::= nexprlist */ + 284, /* (382) nmnum ::= plus_num */ + 284, /* (383) nmnum ::= nm */ + 284, /* (384) nmnum ::= ON */ + 284, /* (385) nmnum ::= DELETE */ + 284, /* (386) nmnum ::= DEFAULT */ + 211, /* (387) plus_num ::= INTEGER|FLOAT */ + 289, /* (388) foreach_clause ::= */ + 289, /* (389) foreach_clause ::= FOR EACH ROW */ + 292, /* (390) trnm ::= nm */ + 293, /* (391) tridxby ::= */ + 294, /* (392) database_kw_opt ::= DATABASE */ + 294, /* (393) database_kw_opt ::= */ + 297, /* (394) kwcolumn_opt ::= */ + 297, /* (395) kwcolumn_opt ::= COLUMNKW */ + 299, /* (396) vtabarglist ::= vtabarg */ + 299, /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ + 300, /* (398) vtabarg ::= vtabarg vtabargtoken */ + 303, /* (399) anylist ::= */ + 303, /* (400) anylist ::= anylist LP anylist RP */ + 303, /* (401) anylist ::= anylist ANY */ + 266, /* (402) with ::= */ + 306, /* (403) windowdefn_list ::= windowdefn */ + 308, /* (404) window ::= frame_opt */ }; /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number @@ -172547,221 +173713,223 @@ static const signed char yyRuleInfoNRhs[] = { -3, /* (185) expr ::= expr COLLATE ID|STRING */ -6, /* (186) expr ::= CAST LP expr AS typetoken RP */ -5, /* (187) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ - -4, /* (188) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ - -6, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ - -5, /* (190) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ - -1, /* (191) term ::= CTIME_KW */ - -5, /* (192) expr ::= LP nexprlist COMMA expr RP */ - -3, /* (193) expr ::= expr AND expr */ - -3, /* (194) expr ::= expr OR expr */ - -3, /* (195) expr ::= expr LT|GT|GE|LE expr */ - -3, /* (196) expr ::= expr EQ|NE expr */ - -3, /* (197) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - -3, /* (198) expr ::= expr PLUS|MINUS expr */ - -3, /* (199) expr ::= expr STAR|SLASH|REM expr */ - -3, /* (200) expr ::= expr CONCAT expr */ - -2, /* (201) likeop ::= NOT LIKE_KW|MATCH */ - -3, /* (202) expr ::= expr likeop expr */ - -5, /* (203) expr ::= expr likeop expr ESCAPE expr */ - -2, /* (204) expr ::= expr ISNULL|NOTNULL */ - -3, /* (205) expr ::= expr NOT NULL */ - -3, /* (206) expr ::= expr IS expr */ - -4, /* (207) expr ::= expr IS NOT expr */ - -6, /* (208) expr ::= expr IS NOT DISTINCT FROM expr */ - -5, /* (209) expr ::= expr IS DISTINCT FROM expr */ - -2, /* (210) expr ::= NOT expr */ - -2, /* (211) expr ::= BITNOT expr */ - -2, /* (212) expr ::= PLUS|MINUS expr */ - -3, /* (213) expr ::= expr PTR expr */ - -1, /* (214) between_op ::= BETWEEN */ - -2, /* (215) between_op ::= NOT BETWEEN */ - -5, /* (216) expr ::= expr between_op expr AND expr */ - -1, /* (217) in_op ::= IN */ - -2, /* (218) in_op ::= NOT IN */ - -5, /* (219) expr ::= expr in_op LP exprlist RP */ - -3, /* (220) expr ::= LP select RP */ - -5, /* (221) expr ::= expr in_op LP select RP */ - -5, /* (222) expr ::= expr in_op nm dbnm paren_exprlist */ - -4, /* (223) expr ::= EXISTS LP select RP */ - -5, /* (224) expr ::= CASE case_operand case_exprlist case_else END */ - -5, /* (225) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - -4, /* (226) case_exprlist ::= WHEN expr THEN expr */ - -2, /* (227) case_else ::= ELSE expr */ - 0, /* (228) case_else ::= */ - 0, /* (229) case_operand ::= */ - 0, /* (230) exprlist ::= */ - -3, /* (231) nexprlist ::= nexprlist COMMA expr */ - -1, /* (232) nexprlist ::= expr */ - 0, /* (233) paren_exprlist ::= */ - -3, /* (234) paren_exprlist ::= LP exprlist RP */ - -12, /* (235) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - -1, /* (236) uniqueflag ::= UNIQUE */ - 0, /* (237) uniqueflag ::= */ - 0, /* (238) eidlist_opt ::= */ - -3, /* (239) eidlist_opt ::= LP eidlist RP */ - -5, /* (240) eidlist ::= eidlist COMMA nm collate sortorder */ - -3, /* (241) eidlist ::= nm collate sortorder */ - 0, /* (242) collate ::= */ - -2, /* (243) collate ::= COLLATE ID|STRING */ - -4, /* (244) cmd ::= DROP INDEX ifexists fullname */ - -2, /* (245) cmd ::= VACUUM vinto */ - -3, /* (246) cmd ::= VACUUM nm vinto */ - -2, /* (247) vinto ::= INTO expr */ - 0, /* (248) vinto ::= */ - -3, /* (249) cmd ::= PRAGMA nm dbnm */ - -5, /* (250) cmd ::= PRAGMA nm dbnm EQ nmnum */ - -6, /* (251) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - -5, /* (252) cmd ::= PRAGMA nm dbnm EQ minus_num */ - -6, /* (253) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - -2, /* (254) plus_num ::= PLUS INTEGER|FLOAT */ - -2, /* (255) minus_num ::= MINUS INTEGER|FLOAT */ - -5, /* (256) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - -11, /* (257) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - -1, /* (258) trigger_time ::= BEFORE|AFTER */ - -2, /* (259) trigger_time ::= INSTEAD OF */ - 0, /* (260) trigger_time ::= */ - -1, /* (261) trigger_event ::= DELETE|INSERT */ - -1, /* (262) trigger_event ::= UPDATE */ - -3, /* (263) trigger_event ::= UPDATE OF idlist */ - 0, /* (264) when_clause ::= */ - -2, /* (265) when_clause ::= WHEN expr */ - -3, /* (266) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - -2, /* (267) trigger_cmd_list ::= trigger_cmd SEMI */ - -3, /* (268) trnm ::= nm DOT nm */ - -3, /* (269) tridxby ::= INDEXED BY nm */ - -2, /* (270) tridxby ::= NOT INDEXED */ - -9, /* (271) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - -8, /* (272) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - -6, /* (273) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - -3, /* (274) trigger_cmd ::= scanpt select scanpt */ - -4, /* (275) expr ::= RAISE LP IGNORE RP */ - -6, /* (276) expr ::= RAISE LP raisetype COMMA nm RP */ - -1, /* (277) raisetype ::= ROLLBACK */ - -1, /* (278) raisetype ::= ABORT */ - -1, /* (279) raisetype ::= FAIL */ - -4, /* (280) cmd ::= DROP TRIGGER ifexists fullname */ - -6, /* (281) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - -3, /* (282) cmd ::= DETACH database_kw_opt expr */ - 0, /* (283) key_opt ::= */ - -2, /* (284) key_opt ::= KEY expr */ - -1, /* (285) cmd ::= REINDEX */ - -3, /* (286) cmd ::= REINDEX nm dbnm */ - -1, /* (287) cmd ::= ANALYZE */ - -3, /* (288) cmd ::= ANALYZE nm dbnm */ - -6, /* (289) cmd ::= ALTER TABLE fullname RENAME TO nm */ - -7, /* (290) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - -6, /* (291) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - -1, /* (292) add_column_fullname ::= fullname */ - -8, /* (293) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - -1, /* (294) cmd ::= create_vtab */ - -4, /* (295) cmd ::= create_vtab LP vtabarglist RP */ - -8, /* (296) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 0, /* (297) vtabarg ::= */ - -1, /* (298) vtabargtoken ::= ANY */ - -3, /* (299) vtabargtoken ::= lp anylist RP */ - -1, /* (300) lp ::= LP */ - -2, /* (301) with ::= WITH wqlist */ - -3, /* (302) with ::= WITH RECURSIVE wqlist */ - -1, /* (303) wqas ::= AS */ - -2, /* (304) wqas ::= AS MATERIALIZED */ - -3, /* (305) wqas ::= AS NOT MATERIALIZED */ - -6, /* (306) wqitem ::= nm eidlist_opt wqas LP select RP */ - -1, /* (307) wqlist ::= wqitem */ - -3, /* (308) wqlist ::= wqlist COMMA wqitem */ - -3, /* (309) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - -5, /* (310) windowdefn ::= nm AS LP window RP */ - -5, /* (311) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - -6, /* (312) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - -4, /* (313) window ::= ORDER BY sortlist frame_opt */ - -5, /* (314) window ::= nm ORDER BY sortlist frame_opt */ - -2, /* (315) window ::= nm frame_opt */ - 0, /* (316) frame_opt ::= */ - -3, /* (317) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - -6, /* (318) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - -1, /* (319) range_or_rows ::= RANGE|ROWS|GROUPS */ - -1, /* (320) frame_bound_s ::= frame_bound */ - -2, /* (321) frame_bound_s ::= UNBOUNDED PRECEDING */ - -1, /* (322) frame_bound_e ::= frame_bound */ - -2, /* (323) frame_bound_e ::= UNBOUNDED FOLLOWING */ - -2, /* (324) frame_bound ::= expr PRECEDING|FOLLOWING */ - -2, /* (325) frame_bound ::= CURRENT ROW */ - 0, /* (326) frame_exclude_opt ::= */ - -2, /* (327) frame_exclude_opt ::= EXCLUDE frame_exclude */ - -2, /* (328) frame_exclude ::= NO OTHERS */ - -2, /* (329) frame_exclude ::= CURRENT ROW */ - -1, /* (330) frame_exclude ::= GROUP|TIES */ - -2, /* (331) window_clause ::= WINDOW windowdefn_list */ - -2, /* (332) filter_over ::= filter_clause over_clause */ - -1, /* (333) filter_over ::= over_clause */ - -1, /* (334) filter_over ::= filter_clause */ - -4, /* (335) over_clause ::= OVER LP window RP */ - -2, /* (336) over_clause ::= OVER nm */ - -5, /* (337) filter_clause ::= FILTER LP WHERE expr RP */ - -1, /* (338) input ::= cmdlist */ - -2, /* (339) cmdlist ::= cmdlist ecmd */ - -1, /* (340) cmdlist ::= ecmd */ - -1, /* (341) ecmd ::= SEMI */ - -2, /* (342) ecmd ::= cmdx SEMI */ - -3, /* (343) ecmd ::= explain cmdx SEMI */ - 0, /* (344) trans_opt ::= */ - -1, /* (345) trans_opt ::= TRANSACTION */ - -2, /* (346) trans_opt ::= TRANSACTION nm */ - -1, /* (347) savepoint_opt ::= SAVEPOINT */ - 0, /* (348) savepoint_opt ::= */ - -2, /* (349) cmd ::= create_table create_table_args */ - -1, /* (350) table_option_set ::= table_option */ - -4, /* (351) columnlist ::= columnlist COMMA columnname carglist */ - -2, /* (352) columnlist ::= columnname carglist */ - -1, /* (353) nm ::= ID|INDEXED|JOIN_KW */ - -1, /* (354) nm ::= STRING */ - -1, /* (355) typetoken ::= typename */ - -1, /* (356) typename ::= ID|STRING */ - -1, /* (357) signed ::= plus_num */ - -1, /* (358) signed ::= minus_num */ - -2, /* (359) carglist ::= carglist ccons */ - 0, /* (360) carglist ::= */ - -2, /* (361) ccons ::= NULL onconf */ - -4, /* (362) ccons ::= GENERATED ALWAYS AS generated */ - -2, /* (363) ccons ::= AS generated */ - -2, /* (364) conslist_opt ::= COMMA conslist */ - -3, /* (365) conslist ::= conslist tconscomma tcons */ - -1, /* (366) conslist ::= tcons */ - 0, /* (367) tconscomma ::= */ - -1, /* (368) defer_subclause_opt ::= defer_subclause */ - -1, /* (369) resolvetype ::= raisetype */ - -1, /* (370) selectnowith ::= oneselect */ - -1, /* (371) oneselect ::= values */ - -2, /* (372) sclp ::= selcollist COMMA */ - -1, /* (373) as ::= ID|STRING */ - -1, /* (374) indexed_opt ::= indexed_by */ - 0, /* (375) returning ::= */ - -1, /* (376) expr ::= term */ - -1, /* (377) likeop ::= LIKE_KW|MATCH */ - -1, /* (378) case_operand ::= expr */ - -1, /* (379) exprlist ::= nexprlist */ - -1, /* (380) nmnum ::= plus_num */ - -1, /* (381) nmnum ::= nm */ - -1, /* (382) nmnum ::= ON */ - -1, /* (383) nmnum ::= DELETE */ - -1, /* (384) nmnum ::= DEFAULT */ - -1, /* (385) plus_num ::= INTEGER|FLOAT */ - 0, /* (386) foreach_clause ::= */ - -3, /* (387) foreach_clause ::= FOR EACH ROW */ - -1, /* (388) trnm ::= nm */ - 0, /* (389) tridxby ::= */ - -1, /* (390) database_kw_opt ::= DATABASE */ - 0, /* (391) database_kw_opt ::= */ - 0, /* (392) kwcolumn_opt ::= */ - -1, /* (393) kwcolumn_opt ::= COLUMNKW */ - -1, /* (394) vtabarglist ::= vtabarg */ - -3, /* (395) vtabarglist ::= vtabarglist COMMA vtabarg */ - -2, /* (396) vtabarg ::= vtabarg vtabargtoken */ - 0, /* (397) anylist ::= */ - -4, /* (398) anylist ::= anylist LP anylist RP */ - -2, /* (399) anylist ::= anylist ANY */ - 0, /* (400) with ::= */ - -1, /* (401) windowdefn_list ::= windowdefn */ - -1, /* (402) window ::= frame_opt */ + -8, /* (188) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + -4, /* (189) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + -6, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + -9, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + -5, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + -1, /* (193) term ::= CTIME_KW */ + -5, /* (194) expr ::= LP nexprlist COMMA expr RP */ + -3, /* (195) expr ::= expr AND expr */ + -3, /* (196) expr ::= expr OR expr */ + -3, /* (197) expr ::= expr LT|GT|GE|LE expr */ + -3, /* (198) expr ::= expr EQ|NE expr */ + -3, /* (199) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + -3, /* (200) expr ::= expr PLUS|MINUS expr */ + -3, /* (201) expr ::= expr STAR|SLASH|REM expr */ + -3, /* (202) expr ::= expr CONCAT expr */ + -2, /* (203) likeop ::= NOT LIKE_KW|MATCH */ + -3, /* (204) expr ::= expr likeop expr */ + -5, /* (205) expr ::= expr likeop expr ESCAPE expr */ + -2, /* (206) expr ::= expr ISNULL|NOTNULL */ + -3, /* (207) expr ::= expr NOT NULL */ + -3, /* (208) expr ::= expr IS expr */ + -4, /* (209) expr ::= expr IS NOT expr */ + -6, /* (210) expr ::= expr IS NOT DISTINCT FROM expr */ + -5, /* (211) expr ::= expr IS DISTINCT FROM expr */ + -2, /* (212) expr ::= NOT expr */ + -2, /* (213) expr ::= BITNOT expr */ + -2, /* (214) expr ::= PLUS|MINUS expr */ + -3, /* (215) expr ::= expr PTR expr */ + -1, /* (216) between_op ::= BETWEEN */ + -2, /* (217) between_op ::= NOT BETWEEN */ + -5, /* (218) expr ::= expr between_op expr AND expr */ + -1, /* (219) in_op ::= IN */ + -2, /* (220) in_op ::= NOT IN */ + -5, /* (221) expr ::= expr in_op LP exprlist RP */ + -3, /* (222) expr ::= LP select RP */ + -5, /* (223) expr ::= expr in_op LP select RP */ + -5, /* (224) expr ::= expr in_op nm dbnm paren_exprlist */ + -4, /* (225) expr ::= EXISTS LP select RP */ + -5, /* (226) expr ::= CASE case_operand case_exprlist case_else END */ + -5, /* (227) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + -4, /* (228) case_exprlist ::= WHEN expr THEN expr */ + -2, /* (229) case_else ::= ELSE expr */ + 0, /* (230) case_else ::= */ + 0, /* (231) case_operand ::= */ + 0, /* (232) exprlist ::= */ + -3, /* (233) nexprlist ::= nexprlist COMMA expr */ + -1, /* (234) nexprlist ::= expr */ + 0, /* (235) paren_exprlist ::= */ + -3, /* (236) paren_exprlist ::= LP exprlist RP */ + -12, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + -1, /* (238) uniqueflag ::= UNIQUE */ + 0, /* (239) uniqueflag ::= */ + 0, /* (240) eidlist_opt ::= */ + -3, /* (241) eidlist_opt ::= LP eidlist RP */ + -5, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */ + -3, /* (243) eidlist ::= nm collate sortorder */ + 0, /* (244) collate ::= */ + -2, /* (245) collate ::= COLLATE ID|STRING */ + -4, /* (246) cmd ::= DROP INDEX ifexists fullname */ + -2, /* (247) cmd ::= VACUUM vinto */ + -3, /* (248) cmd ::= VACUUM nm vinto */ + -2, /* (249) vinto ::= INTO expr */ + 0, /* (250) vinto ::= */ + -3, /* (251) cmd ::= PRAGMA nm dbnm */ + -5, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */ + -6, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + -5, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */ + -6, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + -2, /* (256) plus_num ::= PLUS INTEGER|FLOAT */ + -2, /* (257) minus_num ::= MINUS INTEGER|FLOAT */ + -5, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + -11, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + -1, /* (260) trigger_time ::= BEFORE|AFTER */ + -2, /* (261) trigger_time ::= INSTEAD OF */ + 0, /* (262) trigger_time ::= */ + -1, /* (263) trigger_event ::= DELETE|INSERT */ + -1, /* (264) trigger_event ::= UPDATE */ + -3, /* (265) trigger_event ::= UPDATE OF idlist */ + 0, /* (266) when_clause ::= */ + -2, /* (267) when_clause ::= WHEN expr */ + -3, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + -2, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */ + -3, /* (270) trnm ::= nm DOT nm */ + -3, /* (271) tridxby ::= INDEXED BY nm */ + -2, /* (272) tridxby ::= NOT INDEXED */ + -9, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + -8, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + -6, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + -3, /* (276) trigger_cmd ::= scanpt select scanpt */ + -4, /* (277) expr ::= RAISE LP IGNORE RP */ + -6, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */ + -1, /* (279) raisetype ::= ROLLBACK */ + -1, /* (280) raisetype ::= ABORT */ + -1, /* (281) raisetype ::= FAIL */ + -4, /* (282) cmd ::= DROP TRIGGER ifexists fullname */ + -6, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + -3, /* (284) cmd ::= DETACH database_kw_opt expr */ + 0, /* (285) key_opt ::= */ + -2, /* (286) key_opt ::= KEY expr */ + -1, /* (287) cmd ::= REINDEX */ + -3, /* (288) cmd ::= REINDEX nm dbnm */ + -1, /* (289) cmd ::= ANALYZE */ + -3, /* (290) cmd ::= ANALYZE nm dbnm */ + -6, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */ + -7, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + -6, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + -1, /* (294) add_column_fullname ::= fullname */ + -8, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + -1, /* (296) cmd ::= create_vtab */ + -4, /* (297) cmd ::= create_vtab LP vtabarglist RP */ + -8, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 0, /* (299) vtabarg ::= */ + -1, /* (300) vtabargtoken ::= ANY */ + -3, /* (301) vtabargtoken ::= lp anylist RP */ + -1, /* (302) lp ::= LP */ + -2, /* (303) with ::= WITH wqlist */ + -3, /* (304) with ::= WITH RECURSIVE wqlist */ + -1, /* (305) wqas ::= AS */ + -2, /* (306) wqas ::= AS MATERIALIZED */ + -3, /* (307) wqas ::= AS NOT MATERIALIZED */ + -6, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */ + -1, /* (309) wqlist ::= wqitem */ + -3, /* (310) wqlist ::= wqlist COMMA wqitem */ + -3, /* (311) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + -5, /* (312) windowdefn ::= nm AS LP window RP */ + -5, /* (313) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + -6, /* (314) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + -4, /* (315) window ::= ORDER BY sortlist frame_opt */ + -5, /* (316) window ::= nm ORDER BY sortlist frame_opt */ + -2, /* (317) window ::= nm frame_opt */ + 0, /* (318) frame_opt ::= */ + -3, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + -6, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + -1, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */ + -1, /* (322) frame_bound_s ::= frame_bound */ + -2, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */ + -1, /* (324) frame_bound_e ::= frame_bound */ + -2, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */ + -2, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */ + -2, /* (327) frame_bound ::= CURRENT ROW */ + 0, /* (328) frame_exclude_opt ::= */ + -2, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */ + -2, /* (330) frame_exclude ::= NO OTHERS */ + -2, /* (331) frame_exclude ::= CURRENT ROW */ + -1, /* (332) frame_exclude ::= GROUP|TIES */ + -2, /* (333) window_clause ::= WINDOW windowdefn_list */ + -2, /* (334) filter_over ::= filter_clause over_clause */ + -1, /* (335) filter_over ::= over_clause */ + -1, /* (336) filter_over ::= filter_clause */ + -4, /* (337) over_clause ::= OVER LP window RP */ + -2, /* (338) over_clause ::= OVER nm */ + -5, /* (339) filter_clause ::= FILTER LP WHERE expr RP */ + -1, /* (340) input ::= cmdlist */ + -2, /* (341) cmdlist ::= cmdlist ecmd */ + -1, /* (342) cmdlist ::= ecmd */ + -1, /* (343) ecmd ::= SEMI */ + -2, /* (344) ecmd ::= cmdx SEMI */ + -3, /* (345) ecmd ::= explain cmdx SEMI */ + 0, /* (346) trans_opt ::= */ + -1, /* (347) trans_opt ::= TRANSACTION */ + -2, /* (348) trans_opt ::= TRANSACTION nm */ + -1, /* (349) savepoint_opt ::= SAVEPOINT */ + 0, /* (350) savepoint_opt ::= */ + -2, /* (351) cmd ::= create_table create_table_args */ + -1, /* (352) table_option_set ::= table_option */ + -4, /* (353) columnlist ::= columnlist COMMA columnname carglist */ + -2, /* (354) columnlist ::= columnname carglist */ + -1, /* (355) nm ::= ID|INDEXED|JOIN_KW */ + -1, /* (356) nm ::= STRING */ + -1, /* (357) typetoken ::= typename */ + -1, /* (358) typename ::= ID|STRING */ + -1, /* (359) signed ::= plus_num */ + -1, /* (360) signed ::= minus_num */ + -2, /* (361) carglist ::= carglist ccons */ + 0, /* (362) carglist ::= */ + -2, /* (363) ccons ::= NULL onconf */ + -4, /* (364) ccons ::= GENERATED ALWAYS AS generated */ + -2, /* (365) ccons ::= AS generated */ + -2, /* (366) conslist_opt ::= COMMA conslist */ + -3, /* (367) conslist ::= conslist tconscomma tcons */ + -1, /* (368) conslist ::= tcons */ + 0, /* (369) tconscomma ::= */ + -1, /* (370) defer_subclause_opt ::= defer_subclause */ + -1, /* (371) resolvetype ::= raisetype */ + -1, /* (372) selectnowith ::= oneselect */ + -1, /* (373) oneselect ::= values */ + -2, /* (374) sclp ::= selcollist COMMA */ + -1, /* (375) as ::= ID|STRING */ + -1, /* (376) indexed_opt ::= indexed_by */ + 0, /* (377) returning ::= */ + -1, /* (378) expr ::= term */ + -1, /* (379) likeop ::= LIKE_KW|MATCH */ + -1, /* (380) case_operand ::= expr */ + -1, /* (381) exprlist ::= nexprlist */ + -1, /* (382) nmnum ::= plus_num */ + -1, /* (383) nmnum ::= nm */ + -1, /* (384) nmnum ::= ON */ + -1, /* (385) nmnum ::= DELETE */ + -1, /* (386) nmnum ::= DEFAULT */ + -1, /* (387) plus_num ::= INTEGER|FLOAT */ + 0, /* (388) foreach_clause ::= */ + -3, /* (389) foreach_clause ::= FOR EACH ROW */ + -1, /* (390) trnm ::= nm */ + 0, /* (391) tridxby ::= */ + -1, /* (392) database_kw_opt ::= DATABASE */ + 0, /* (393) database_kw_opt ::= */ + 0, /* (394) kwcolumn_opt ::= */ + -1, /* (395) kwcolumn_opt ::= COLUMNKW */ + -1, /* (396) vtabarglist ::= vtabarg */ + -3, /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ + -2, /* (398) vtabarg ::= vtabarg vtabargtoken */ + 0, /* (399) anylist ::= */ + -4, /* (400) anylist ::= anylist LP anylist RP */ + -2, /* (401) anylist ::= anylist ANY */ + 0, /* (402) with ::= */ + -1, /* (403) windowdefn_list ::= windowdefn */ + -1, /* (404) window ::= frame_opt */ }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -172821,7 +173989,7 @@ static YYACTIONTYPE yy_reduce( case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); - case 319: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==319); + case 321: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==321); {yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/} break; case 8: /* cmd ::= COMMIT|END trans_opt */ @@ -172858,7 +174026,7 @@ static YYACTIONTYPE yy_reduce( case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72); case 81: /* ifexists ::= */ yytestcase(yyruleno==81); case 98: /* distinct ::= */ yytestcase(yyruleno==98); - case 242: /* collate ::= */ yytestcase(yyruleno==242); + case 244: /* collate ::= */ yytestcase(yyruleno==244); {yymsp[1].minor.yy394 = 0;} break; case 16: /* ifnotexists ::= IF NOT EXISTS */ @@ -173042,9 +174210,9 @@ static YYACTIONTYPE yy_reduce( break; case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80); - case 215: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==215); - case 218: /* in_op ::= NOT IN */ yytestcase(yyruleno==218); - case 243: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==243); + case 217: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==217); + case 220: /* in_op ::= NOT IN */ yytestcase(yyruleno==220); + case 245: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==245); {yymsp[-1].minor.yy394 = 1;} break; case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ @@ -173193,9 +174361,9 @@ static YYACTIONTYPE yy_reduce( case 99: /* sclp ::= */ case 132: /* orderby_opt ::= */ yytestcase(yyruleno==132); case 142: /* groupby_opt ::= */ yytestcase(yyruleno==142); - case 230: /* exprlist ::= */ yytestcase(yyruleno==230); - case 233: /* paren_exprlist ::= */ yytestcase(yyruleno==233); - case 238: /* eidlist_opt ::= */ yytestcase(yyruleno==238); + case 232: /* exprlist ::= */ yytestcase(yyruleno==232); + case 235: /* paren_exprlist ::= */ yytestcase(yyruleno==235); + case 240: /* eidlist_opt ::= */ yytestcase(yyruleno==240); {yymsp[1].minor.yy322 = 0;} break; case 100: /* selcollist ::= sclp scanpt expr scanpt as */ @@ -173224,8 +174392,8 @@ static YYACTIONTYPE yy_reduce( break; case 103: /* as ::= AS nm */ case 115: /* dbnm ::= DOT nm */ yytestcase(yyruleno==115); - case 254: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==254); - case 255: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==255); + case 256: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==256); + case 257: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==257); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; case 105: /* from ::= */ @@ -173397,16 +174565,16 @@ static YYACTIONTYPE yy_reduce( case 146: /* limit_opt ::= */ yytestcase(yyruleno==146); case 151: /* where_opt ::= */ yytestcase(yyruleno==151); case 153: /* where_opt_ret ::= */ yytestcase(yyruleno==153); - case 228: /* case_else ::= */ yytestcase(yyruleno==228); - case 229: /* case_operand ::= */ yytestcase(yyruleno==229); - case 248: /* vinto ::= */ yytestcase(yyruleno==248); + case 230: /* case_else ::= */ yytestcase(yyruleno==230); + case 231: /* case_operand ::= */ yytestcase(yyruleno==231); + case 250: /* vinto ::= */ yytestcase(yyruleno==250); {yymsp[1].minor.yy528 = 0;} break; case 145: /* having_opt ::= HAVING expr */ case 152: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==152); case 154: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==154); - case 227: /* case_else ::= ELSE expr */ yytestcase(yyruleno==227); - case 247: /* vinto ::= INTO expr */ yytestcase(yyruleno==247); + case 229: /* case_else ::= ELSE expr */ yytestcase(yyruleno==229); + case 249: /* vinto ::= INTO expr */ yytestcase(yyruleno==249); {yymsp[-1].minor.yy528 = yymsp[0].minor.yy528;} break; case 147: /* limit_opt ::= LIMIT expr */ @@ -173592,33 +174760,48 @@ static YYACTIONTYPE yy_reduce( } yymsp[-4].minor.yy528 = yylhsminor.yy528; break; - case 188: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + case 188: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy322, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy394); + sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy528, yymsp[-1].minor.yy322); +} + yymsp[-7].minor.yy528 = yylhsminor.yy528; + break; + case 189: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); } yymsp[-3].minor.yy528 = yylhsminor.yy528; break; - case 189: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy322, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy394); sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); } yymsp[-5].minor.yy528 = yylhsminor.yy528; break; - case 190: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + case 191: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy322, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy394); + sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); + sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy528, yymsp[-2].minor.yy322); +} + yymsp[-8].minor.yy528 = yylhsminor.yy528; + break; + case 192: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); } yymsp[-4].minor.yy528 = yylhsminor.yy528; break; - case 191: /* term ::= CTIME_KW */ + case 193: /* term ::= CTIME_KW */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); } yymsp[0].minor.yy528 = yylhsminor.yy528; break; - case 192: /* expr ::= LP nexprlist COMMA expr RP */ + case 194: /* expr ::= LP nexprlist COMMA expr RP */ { ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528); yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); @@ -173632,22 +174815,22 @@ static YYACTIONTYPE yy_reduce( } } break; - case 193: /* expr ::= expr AND expr */ + case 195: /* expr ::= expr AND expr */ {yymsp[-2].minor.yy528=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} break; - case 194: /* expr ::= expr OR expr */ - case 195: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==195); - case 196: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==196); - case 197: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==197); - case 198: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==198); - case 199: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==199); - case 200: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==200); + case 196: /* expr ::= expr OR expr */ + case 197: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==197); + case 198: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==198); + case 199: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==199); + case 200: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==200); + case 201: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==201); + case 202: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==202); {yymsp[-2].minor.yy528=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} break; - case 201: /* likeop ::= NOT LIKE_KW|MATCH */ + case 203: /* likeop ::= NOT LIKE_KW|MATCH */ {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} break; - case 202: /* expr ::= expr likeop expr */ + case 204: /* expr ::= expr likeop expr */ { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; @@ -173659,7 +174842,7 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-2].minor.yy528 ) yymsp[-2].minor.yy528->flags |= EP_InfixFunc; } break; - case 203: /* expr ::= expr likeop expr ESCAPE expr */ + case 205: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; @@ -173672,47 +174855,47 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-4].minor.yy528 ) yymsp[-4].minor.yy528->flags |= EP_InfixFunc; } break; - case 204: /* expr ::= expr ISNULL|NOTNULL */ + case 206: /* expr ::= expr ISNULL|NOTNULL */ {yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy528,0);} break; - case 205: /* expr ::= expr NOT NULL */ + case 207: /* expr ::= expr NOT NULL */ {yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy528,0);} break; - case 206: /* expr ::= expr IS expr */ + case 208: /* expr ::= expr IS expr */ { yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy528,yymsp[0].minor.yy528); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-2].minor.yy528, TK_ISNULL); } break; - case 207: /* expr ::= expr IS NOT expr */ + case 209: /* expr ::= expr IS NOT expr */ { yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy528,yymsp[0].minor.yy528); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-3].minor.yy528, TK_NOTNULL); } break; - case 208: /* expr ::= expr IS NOT DISTINCT FROM expr */ + case 210: /* expr ::= expr IS NOT DISTINCT FROM expr */ { yymsp[-5].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy528,yymsp[0].minor.yy528); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-5].minor.yy528, TK_ISNULL); } break; - case 209: /* expr ::= expr IS DISTINCT FROM expr */ + case 211: /* expr ::= expr IS DISTINCT FROM expr */ { yymsp[-4].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy528,yymsp[0].minor.yy528); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-4].minor.yy528, TK_NOTNULL); } break; - case 210: /* expr ::= NOT expr */ - case 211: /* expr ::= BITNOT expr */ yytestcase(yyruleno==211); + case 212: /* expr ::= NOT expr */ + case 213: /* expr ::= BITNOT expr */ yytestcase(yyruleno==213); {yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy528, 0);/*A-overwrites-B*/} break; - case 212: /* expr ::= PLUS|MINUS expr */ + case 214: /* expr ::= PLUS|MINUS expr */ { yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy528, 0); /*A-overwrites-B*/ } break; - case 213: /* expr ::= expr PTR expr */ + case 215: /* expr ::= expr PTR expr */ { ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy528); pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy528); @@ -173720,11 +174903,11 @@ static YYACTIONTYPE yy_reduce( } yymsp[-2].minor.yy528 = yylhsminor.yy528; break; - case 214: /* between_op ::= BETWEEN */ - case 217: /* in_op ::= IN */ yytestcase(yyruleno==217); + case 216: /* between_op ::= BETWEEN */ + case 219: /* in_op ::= IN */ yytestcase(yyruleno==219); {yymsp[0].minor.yy394 = 0;} break; - case 216: /* expr ::= expr between_op expr AND expr */ + case 218: /* expr ::= expr between_op expr AND expr */ { ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528); @@ -173737,7 +174920,7 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; - case 219: /* expr ::= expr in_op LP exprlist RP */ + case 221: /* expr ::= expr in_op LP exprlist RP */ { if( yymsp[-1].minor.yy322==0 ){ /* Expressions of the form @@ -173783,20 +174966,20 @@ static YYACTIONTYPE yy_reduce( } } break; - case 220: /* expr ::= LP select RP */ + case 222: /* expr ::= LP select RP */ { yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy528, yymsp[-1].minor.yy47); } break; - case 221: /* expr ::= expr in_op LP select RP */ + case 223: /* expr ::= expr in_op LP select RP */ { yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, yymsp[-1].minor.yy47); if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; - case 222: /* expr ::= expr in_op nm dbnm paren_exprlist */ + case 224: /* expr ::= expr in_op nm dbnm paren_exprlist */ { SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); @@ -173806,14 +174989,14 @@ static YYACTIONTYPE yy_reduce( if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; - case 223: /* expr ::= EXISTS LP select RP */ + case 225: /* expr ::= EXISTS LP select RP */ { Expr *p; p = yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy47); } break; - case 224: /* expr ::= CASE case_operand case_exprlist case_else END */ + case 226: /* expr ::= CASE case_operand case_exprlist case_else END */ { yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy528, 0); if( yymsp[-4].minor.yy528 ){ @@ -173825,29 +175008,29 @@ static YYACTIONTYPE yy_reduce( } } break; - case 225: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 227: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy528); yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy528); } break; - case 226: /* case_exprlist ::= WHEN expr THEN expr */ + case 228: /* case_exprlist ::= WHEN expr THEN expr */ { yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy528); } break; - case 231: /* nexprlist ::= nexprlist COMMA expr */ + case 233: /* nexprlist ::= nexprlist COMMA expr */ {yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy528);} break; - case 232: /* nexprlist ::= expr */ + case 234: /* nexprlist ::= expr */ {yymsp[0].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy528); /*A-overwrites-Y*/} break; - case 234: /* paren_exprlist ::= LP exprlist RP */ - case 239: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==239); + case 236: /* paren_exprlist ::= LP exprlist RP */ + case 241: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==241); {yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;} break; - case 235: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 237: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy394, @@ -173857,48 +175040,48 @@ static YYACTIONTYPE yy_reduce( } } break; - case 236: /* uniqueflag ::= UNIQUE */ - case 278: /* raisetype ::= ABORT */ yytestcase(yyruleno==278); + case 238: /* uniqueflag ::= UNIQUE */ + case 280: /* raisetype ::= ABORT */ yytestcase(yyruleno==280); {yymsp[0].minor.yy394 = OE_Abort;} break; - case 237: /* uniqueflag ::= */ + case 239: /* uniqueflag ::= */ {yymsp[1].minor.yy394 = OE_None;} break; - case 240: /* eidlist ::= eidlist COMMA nm collate sortorder */ + case 242: /* eidlist ::= eidlist COMMA nm collate sortorder */ { yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); } break; - case 241: /* eidlist ::= nm collate sortorder */ + case 243: /* eidlist ::= nm collate sortorder */ { yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); /*A-overwrites-Y*/ } break; - case 244: /* cmd ::= DROP INDEX ifexists fullname */ + case 246: /* cmd ::= DROP INDEX ifexists fullname */ {sqlite3DropIndex(pParse, yymsp[0].minor.yy131, yymsp[-1].minor.yy394);} break; - case 245: /* cmd ::= VACUUM vinto */ + case 247: /* cmd ::= VACUUM vinto */ {sqlite3Vacuum(pParse,0,yymsp[0].minor.yy528);} break; - case 246: /* cmd ::= VACUUM nm vinto */ + case 248: /* cmd ::= VACUUM nm vinto */ {sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy528);} break; - case 249: /* cmd ::= PRAGMA nm dbnm */ + case 251: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 250: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 252: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 251: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 253: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 252: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 254: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 253: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 255: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; - case 256: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 258: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; @@ -173906,50 +175089,50 @@ static YYACTIONTYPE yy_reduce( sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy33, &all); } break; - case 257: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 259: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy394, yymsp[-4].minor.yy180.a, yymsp[-4].minor.yy180.b, yymsp[-2].minor.yy131, yymsp[0].minor.yy528, yymsp[-10].minor.yy394, yymsp[-8].minor.yy394); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 258: /* trigger_time ::= BEFORE|AFTER */ + case 260: /* trigger_time ::= BEFORE|AFTER */ { yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/ } break; - case 259: /* trigger_time ::= INSTEAD OF */ + case 261: /* trigger_time ::= INSTEAD OF */ { yymsp[-1].minor.yy394 = TK_INSTEAD;} break; - case 260: /* trigger_time ::= */ + case 262: /* trigger_time ::= */ { yymsp[1].minor.yy394 = TK_BEFORE; } break; - case 261: /* trigger_event ::= DELETE|INSERT */ - case 262: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==262); + case 263: /* trigger_event ::= DELETE|INSERT */ + case 264: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==264); {yymsp[0].minor.yy180.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy180.b = 0;} break; - case 263: /* trigger_event ::= UPDATE OF idlist */ + case 265: /* trigger_event ::= UPDATE OF idlist */ {yymsp[-2].minor.yy180.a = TK_UPDATE; yymsp[-2].minor.yy180.b = yymsp[0].minor.yy254;} break; - case 264: /* when_clause ::= */ - case 283: /* key_opt ::= */ yytestcase(yyruleno==283); + case 266: /* when_clause ::= */ + case 285: /* key_opt ::= */ yytestcase(yyruleno==285); { yymsp[1].minor.yy528 = 0; } break; - case 265: /* when_clause ::= WHEN expr */ - case 284: /* key_opt ::= KEY expr */ yytestcase(yyruleno==284); + case 267: /* when_clause ::= WHEN expr */ + case 286: /* key_opt ::= KEY expr */ yytestcase(yyruleno==286); { yymsp[-1].minor.yy528 = yymsp[0].minor.yy528; } break; - case 266: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 268: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { assert( yymsp[-2].minor.yy33!=0 ); yymsp[-2].minor.yy33->pLast->pNext = yymsp[-1].minor.yy33; yymsp[-2].minor.yy33->pLast = yymsp[-1].minor.yy33; } break; - case 267: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 269: /* trigger_cmd_list ::= trigger_cmd SEMI */ { assert( yymsp[-1].minor.yy33!=0 ); yymsp[-1].minor.yy33->pLast = yymsp[-1].minor.yy33; } break; - case 268: /* trnm ::= nm DOT nm */ + case 270: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, @@ -173957,39 +175140,39 @@ static YYACTIONTYPE yy_reduce( "statements within triggers"); } break; - case 269: /* tridxby ::= INDEXED BY nm */ + case 271: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 270: /* tridxby ::= NOT INDEXED */ + case 272: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 271: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + case 273: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ {yylhsminor.yy33 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy131, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528, yymsp[-7].minor.yy394, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy522);} yymsp[-8].minor.yy33 = yylhsminor.yy33; break; - case 272: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + case 274: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ { yylhsminor.yy33 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy254,yymsp[-2].minor.yy47,yymsp[-6].minor.yy394,yymsp[-1].minor.yy444,yymsp[-7].minor.yy522,yymsp[0].minor.yy522);/*yylhsminor.yy33-overwrites-yymsp[-6].minor.yy394*/ } yymsp[-7].minor.yy33 = yylhsminor.yy33; break; - case 273: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + case 275: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ {yylhsminor.yy33 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy528, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy522);} yymsp[-5].minor.yy33 = yylhsminor.yy33; break; - case 274: /* trigger_cmd ::= scanpt select scanpt */ + case 276: /* trigger_cmd ::= scanpt select scanpt */ {yylhsminor.yy33 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy47, yymsp[-2].minor.yy522, yymsp[0].minor.yy522); /*yylhsminor.yy33-overwrites-yymsp[-1].minor.yy47*/} yymsp[-2].minor.yy33 = yylhsminor.yy33; break; - case 275: /* expr ::= RAISE LP IGNORE RP */ + case 277: /* expr ::= RAISE LP IGNORE RP */ { yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); if( yymsp[-3].minor.yy528 ){ @@ -173997,7 +175180,7 @@ static YYACTIONTYPE yy_reduce( } } break; - case 276: /* expr ::= RAISE LP raisetype COMMA nm RP */ + case 278: /* expr ::= RAISE LP raisetype COMMA nm RP */ { yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); if( yymsp[-5].minor.yy528 ) { @@ -174005,114 +175188,114 @@ static YYACTIONTYPE yy_reduce( } } break; - case 277: /* raisetype ::= ROLLBACK */ + case 279: /* raisetype ::= ROLLBACK */ {yymsp[0].minor.yy394 = OE_Rollback;} break; - case 279: /* raisetype ::= FAIL */ + case 281: /* raisetype ::= FAIL */ {yymsp[0].minor.yy394 = OE_Fail;} break; - case 280: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 282: /* cmd ::= DROP TRIGGER ifexists fullname */ { sqlite3DropTrigger(pParse,yymsp[0].minor.yy131,yymsp[-1].minor.yy394); } break; - case 281: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 283: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { sqlite3Attach(pParse, yymsp[-3].minor.yy528, yymsp[-1].minor.yy528, yymsp[0].minor.yy528); } break; - case 282: /* cmd ::= DETACH database_kw_opt expr */ + case 284: /* cmd ::= DETACH database_kw_opt expr */ { sqlite3Detach(pParse, yymsp[0].minor.yy528); } break; - case 285: /* cmd ::= REINDEX */ + case 287: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 286: /* cmd ::= REINDEX nm dbnm */ + case 288: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 287: /* cmd ::= ANALYZE */ + case 289: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 288: /* cmd ::= ANALYZE nm dbnm */ + case 290: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 289: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 291: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy131,&yymsp[0].minor.yy0); } break; - case 290: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 292: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 291: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + case 293: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ { sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy131, &yymsp[0].minor.yy0); } break; - case 292: /* add_column_fullname ::= fullname */ + case 294: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy131); } break; - case 293: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + case 295: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ { sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy131, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); } break; - case 294: /* cmd ::= create_vtab */ + case 296: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 295: /* cmd ::= create_vtab LP vtabarglist RP */ + case 297: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 296: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 298: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy394); } break; - case 297: /* vtabarg ::= */ + case 299: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 298: /* vtabargtoken ::= ANY */ - case 299: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==299); - case 300: /* lp ::= LP */ yytestcase(yyruleno==300); + case 300: /* vtabargtoken ::= ANY */ + case 301: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==301); + case 302: /* lp ::= LP */ yytestcase(yyruleno==302); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 301: /* with ::= WITH wqlist */ - case 302: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==302); + case 303: /* with ::= WITH wqlist */ + case 304: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==304); { sqlite3WithPush(pParse, yymsp[0].minor.yy521, 1); } break; - case 303: /* wqas ::= AS */ + case 305: /* wqas ::= AS */ {yymsp[0].minor.yy516 = M10d_Any;} break; - case 304: /* wqas ::= AS MATERIALIZED */ + case 306: /* wqas ::= AS MATERIALIZED */ {yymsp[-1].minor.yy516 = M10d_Yes;} break; - case 305: /* wqas ::= AS NOT MATERIALIZED */ + case 307: /* wqas ::= AS NOT MATERIALIZED */ {yymsp[-2].minor.yy516 = M10d_No;} break; - case 306: /* wqitem ::= nm eidlist_opt wqas LP select RP */ + case 308: /* wqitem ::= nm eidlist_opt wqas LP select RP */ { yymsp[-5].minor.yy385 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy47, yymsp[-3].minor.yy516); /*A-overwrites-X*/ } break; - case 307: /* wqlist ::= wqitem */ + case 309: /* wqlist ::= wqitem */ { yymsp[0].minor.yy521 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy385); /*A-overwrites-X*/ } break; - case 308: /* wqlist ::= wqlist COMMA wqitem */ + case 310: /* wqlist ::= wqlist COMMA wqitem */ { yymsp[-2].minor.yy521 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy521, yymsp[0].minor.yy385); } break; - case 309: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ + case 311: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ { assert( yymsp[0].minor.yy41!=0 ); sqlite3WindowChain(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy41); @@ -174121,7 +175304,7 @@ static YYACTIONTYPE yy_reduce( } yymsp[-2].minor.yy41 = yylhsminor.yy41; break; - case 310: /* windowdefn ::= nm AS LP window RP */ + case 312: /* windowdefn ::= nm AS LP window RP */ { if( ALWAYS(yymsp[-1].minor.yy41) ){ yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); @@ -174130,83 +175313,83 @@ static YYACTIONTYPE yy_reduce( } yymsp[-4].minor.yy41 = yylhsminor.yy41; break; - case 311: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + case 313: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ { yymsp[-4].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, 0); } break; - case 312: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + case 314: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ { yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, &yymsp[-5].minor.yy0); } yymsp[-5].minor.yy41 = yylhsminor.yy41; break; - case 313: /* window ::= ORDER BY sortlist frame_opt */ + case 315: /* window ::= ORDER BY sortlist frame_opt */ { yymsp[-3].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, 0); } break; - case 314: /* window ::= nm ORDER BY sortlist frame_opt */ + case 316: /* window ::= nm ORDER BY sortlist frame_opt */ { yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0); } yymsp[-4].minor.yy41 = yylhsminor.yy41; break; - case 315: /* window ::= nm frame_opt */ + case 317: /* window ::= nm frame_opt */ { yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, 0, &yymsp[-1].minor.yy0); } yymsp[-1].minor.yy41 = yylhsminor.yy41; break; - case 316: /* frame_opt ::= */ + case 318: /* frame_opt ::= */ { yymsp[1].minor.yy41 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); } break; - case 317: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + case 319: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ { yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy394, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy516); } yymsp[-2].minor.yy41 = yylhsminor.yy41; break; - case 318: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + case 320: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ { yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy394, yymsp[-3].minor.yy595.eType, yymsp[-3].minor.yy595.pExpr, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, yymsp[0].minor.yy516); } yymsp[-5].minor.yy41 = yylhsminor.yy41; break; - case 320: /* frame_bound_s ::= frame_bound */ - case 322: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==322); + case 322: /* frame_bound_s ::= frame_bound */ + case 324: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==324); {yylhsminor.yy595 = yymsp[0].minor.yy595;} yymsp[0].minor.yy595 = yylhsminor.yy595; break; - case 321: /* frame_bound_s ::= UNBOUNDED PRECEDING */ - case 323: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==323); - case 325: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==325); + case 323: /* frame_bound_s ::= UNBOUNDED PRECEDING */ + case 325: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==325); + case 327: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==327); {yylhsminor.yy595.eType = yymsp[-1].major; yylhsminor.yy595.pExpr = 0;} yymsp[-1].minor.yy595 = yylhsminor.yy595; break; - case 324: /* frame_bound ::= expr PRECEDING|FOLLOWING */ + case 326: /* frame_bound ::= expr PRECEDING|FOLLOWING */ {yylhsminor.yy595.eType = yymsp[0].major; yylhsminor.yy595.pExpr = yymsp[-1].minor.yy528;} yymsp[-1].minor.yy595 = yylhsminor.yy595; break; - case 326: /* frame_exclude_opt ::= */ + case 328: /* frame_exclude_opt ::= */ {yymsp[1].minor.yy516 = 0;} break; - case 327: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ + case 329: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ {yymsp[-1].minor.yy516 = yymsp[0].minor.yy516;} break; - case 328: /* frame_exclude ::= NO OTHERS */ - case 329: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==329); + case 330: /* frame_exclude ::= NO OTHERS */ + case 331: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==331); {yymsp[-1].minor.yy516 = yymsp[-1].major; /*A-overwrites-X*/} break; - case 330: /* frame_exclude ::= GROUP|TIES */ + case 332: /* frame_exclude ::= GROUP|TIES */ {yymsp[0].minor.yy516 = yymsp[0].major; /*A-overwrites-X*/} break; - case 331: /* window_clause ::= WINDOW windowdefn_list */ + case 333: /* window_clause ::= WINDOW windowdefn_list */ { yymsp[-1].minor.yy41 = yymsp[0].minor.yy41; } break; - case 332: /* filter_over ::= filter_clause over_clause */ + case 334: /* filter_over ::= filter_clause over_clause */ { if( yymsp[0].minor.yy41 ){ yymsp[0].minor.yy41->pFilter = yymsp[-1].minor.yy528; @@ -174217,13 +175400,13 @@ static YYACTIONTYPE yy_reduce( } yymsp[-1].minor.yy41 = yylhsminor.yy41; break; - case 333: /* filter_over ::= over_clause */ + case 335: /* filter_over ::= over_clause */ { yylhsminor.yy41 = yymsp[0].minor.yy41; } yymsp[0].minor.yy41 = yylhsminor.yy41; break; - case 334: /* filter_over ::= filter_clause */ + case 336: /* filter_over ::= filter_clause */ { yylhsminor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( yylhsminor.yy41 ){ @@ -174235,13 +175418,13 @@ static YYACTIONTYPE yy_reduce( } yymsp[0].minor.yy41 = yylhsminor.yy41; break; - case 335: /* over_clause ::= OVER LP window RP */ + case 337: /* over_clause ::= OVER LP window RP */ { yymsp[-3].minor.yy41 = yymsp[-1].minor.yy41; assert( yymsp[-3].minor.yy41!=0 ); } break; - case 336: /* over_clause ::= OVER nm */ + case 338: /* over_clause ::= OVER nm */ { yymsp[-1].minor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( yymsp[-1].minor.yy41 ){ @@ -174249,75 +175432,75 @@ static YYACTIONTYPE yy_reduce( } } break; - case 337: /* filter_clause ::= FILTER LP WHERE expr RP */ + case 339: /* filter_clause ::= FILTER LP WHERE expr RP */ { yymsp[-4].minor.yy528 = yymsp[-1].minor.yy528; } break; default: - /* (338) input ::= cmdlist */ yytestcase(yyruleno==338); - /* (339) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==339); - /* (340) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=340); - /* (341) ecmd ::= SEMI */ yytestcase(yyruleno==341); - /* (342) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==342); - /* (343) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=343); - /* (344) trans_opt ::= */ yytestcase(yyruleno==344); - /* (345) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==345); - /* (346) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==346); - /* (347) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==347); - /* (348) savepoint_opt ::= */ yytestcase(yyruleno==348); - /* (349) cmd ::= create_table create_table_args */ yytestcase(yyruleno==349); - /* (350) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=350); - /* (351) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==351); - /* (352) columnlist ::= columnname carglist */ yytestcase(yyruleno==352); - /* (353) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==353); - /* (354) nm ::= STRING */ yytestcase(yyruleno==354); - /* (355) typetoken ::= typename */ yytestcase(yyruleno==355); - /* (356) typename ::= ID|STRING */ yytestcase(yyruleno==356); - /* (357) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=357); - /* (358) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=358); - /* (359) carglist ::= carglist ccons */ yytestcase(yyruleno==359); - /* (360) carglist ::= */ yytestcase(yyruleno==360); - /* (361) ccons ::= NULL onconf */ yytestcase(yyruleno==361); - /* (362) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==362); - /* (363) ccons ::= AS generated */ yytestcase(yyruleno==363); - /* (364) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==364); - /* (365) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==365); - /* (366) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=366); - /* (367) tconscomma ::= */ yytestcase(yyruleno==367); - /* (368) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=368); - /* (369) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=369); - /* (370) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=370); - /* (371) oneselect ::= values */ yytestcase(yyruleno==371); - /* (372) sclp ::= selcollist COMMA */ yytestcase(yyruleno==372); - /* (373) as ::= ID|STRING */ yytestcase(yyruleno==373); - /* (374) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=374); - /* (375) returning ::= */ yytestcase(yyruleno==375); - /* (376) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=376); - /* (377) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==377); - /* (378) case_operand ::= expr */ yytestcase(yyruleno==378); - /* (379) exprlist ::= nexprlist */ yytestcase(yyruleno==379); - /* (380) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=380); - /* (381) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=381); - /* (382) nmnum ::= ON */ yytestcase(yyruleno==382); - /* (383) nmnum ::= DELETE */ yytestcase(yyruleno==383); - /* (384) nmnum ::= DEFAULT */ yytestcase(yyruleno==384); - /* (385) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==385); - /* (386) foreach_clause ::= */ yytestcase(yyruleno==386); - /* (387) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==387); - /* (388) trnm ::= nm */ yytestcase(yyruleno==388); - /* (389) tridxby ::= */ yytestcase(yyruleno==389); - /* (390) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==390); - /* (391) database_kw_opt ::= */ yytestcase(yyruleno==391); - /* (392) kwcolumn_opt ::= */ yytestcase(yyruleno==392); - /* (393) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==393); - /* (394) vtabarglist ::= vtabarg */ yytestcase(yyruleno==394); - /* (395) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==395); - /* (396) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==396); - /* (397) anylist ::= */ yytestcase(yyruleno==397); - /* (398) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==398); - /* (399) anylist ::= anylist ANY */ yytestcase(yyruleno==399); - /* (400) with ::= */ yytestcase(yyruleno==400); - /* (401) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=401); - /* (402) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=402); + /* (340) input ::= cmdlist */ yytestcase(yyruleno==340); + /* (341) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==341); + /* (342) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=342); + /* (343) ecmd ::= SEMI */ yytestcase(yyruleno==343); + /* (344) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==344); + /* (345) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=345); + /* (346) trans_opt ::= */ yytestcase(yyruleno==346); + /* (347) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==347); + /* (348) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==348); + /* (349) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==349); + /* (350) savepoint_opt ::= */ yytestcase(yyruleno==350); + /* (351) cmd ::= create_table create_table_args */ yytestcase(yyruleno==351); + /* (352) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=352); + /* (353) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==353); + /* (354) columnlist ::= columnname carglist */ yytestcase(yyruleno==354); + /* (355) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==355); + /* (356) nm ::= STRING */ yytestcase(yyruleno==356); + /* (357) typetoken ::= typename */ yytestcase(yyruleno==357); + /* (358) typename ::= ID|STRING */ yytestcase(yyruleno==358); + /* (359) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=359); + /* (360) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=360); + /* (361) carglist ::= carglist ccons */ yytestcase(yyruleno==361); + /* (362) carglist ::= */ yytestcase(yyruleno==362); + /* (363) ccons ::= NULL onconf */ yytestcase(yyruleno==363); + /* (364) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==364); + /* (365) ccons ::= AS generated */ yytestcase(yyruleno==365); + /* (366) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==366); + /* (367) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==367); + /* (368) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=368); + /* (369) tconscomma ::= */ yytestcase(yyruleno==369); + /* (370) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=370); + /* (371) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=371); + /* (372) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=372); + /* (373) oneselect ::= values */ yytestcase(yyruleno==373); + /* (374) sclp ::= selcollist COMMA */ yytestcase(yyruleno==374); + /* (375) as ::= ID|STRING */ yytestcase(yyruleno==375); + /* (376) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=376); + /* (377) returning ::= */ yytestcase(yyruleno==377); + /* (378) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=378); + /* (379) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==379); + /* (380) case_operand ::= expr */ yytestcase(yyruleno==380); + /* (381) exprlist ::= nexprlist */ yytestcase(yyruleno==381); + /* (382) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=382); + /* (383) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=383); + /* (384) nmnum ::= ON */ yytestcase(yyruleno==384); + /* (385) nmnum ::= DELETE */ yytestcase(yyruleno==385); + /* (386) nmnum ::= DEFAULT */ yytestcase(yyruleno==386); + /* (387) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==387); + /* (388) foreach_clause ::= */ yytestcase(yyruleno==388); + /* (389) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==389); + /* (390) trnm ::= nm */ yytestcase(yyruleno==390); + /* (391) tridxby ::= */ yytestcase(yyruleno==391); + /* (392) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==392); + /* (393) database_kw_opt ::= */ yytestcase(yyruleno==393); + /* (394) kwcolumn_opt ::= */ yytestcase(yyruleno==394); + /* (395) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==395); + /* (396) vtabarglist ::= vtabarg */ yytestcase(yyruleno==396); + /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==397); + /* (398) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==398); + /* (399) anylist ::= */ yytestcase(yyruleno==399); + /* (400) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==400); + /* (401) anylist ::= anylist ANY */ yytestcase(yyruleno==401); + /* (402) with ::= */ yytestcase(yyruleno==402); + /* (403) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=403); + /* (404) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=404); break; /********** End reduce actions ************************************************/ }; @@ -176441,7 +177624,9 @@ SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*); #ifdef SQLITE_ENABLE_STMTVTAB SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*); #endif - +#ifdef SQLITE_EXTRA_AUTOEXT +int SQLITE_EXTRA_AUTOEXT(sqlite3*); +#endif /* ** An array of pointers to extension initializer functions for ** built-in extensions. @@ -176475,6 +177660,9 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { #ifdef SQLITE_ENABLE_BYTECODE_VTAB sqlite3VdbeBytecodeVtabInit, #endif +#ifdef SQLITE_EXTRA_AUTOEXT + SQLITE_EXTRA_AUTOEXT, +#endif }; #ifndef SQLITE_AMALGAMATION @@ -176548,6 +177736,32 @@ SQLITE_API char *sqlite3_temp_directory = 0; */ SQLITE_API char *sqlite3_data_directory = 0; +/* +** Determine whether or not high-precision (long double) floating point +** math works correctly on CPU currently running. +*/ +static SQLITE_NOINLINE int hasHighPrecisionDouble(int rc){ + if( sizeof(LONGDOUBLE_TYPE)<=8 ){ + /* If the size of "long double" is not more than 8, then + ** high-precision math is not possible. */ + return 0; + }else{ + /* Just because sizeof(long double)>8 does not mean that the underlying + ** hardware actually supports high-precision floating point. For example, + ** clearing the 0x100 bit in the floating-point control word on Intel + ** processors will make long double work like double, even though long + ** double takes up more space. The only way to determine if long double + ** actually works is to run an experiment. */ + LONGDOUBLE_TYPE a, b, c; + rc++; + a = 1.0+rc*0.1; + b = 1.0e+18+rc*25.0; + c = a+b; + return b!=c; + } +} + + /* ** Initialize SQLite. ** @@ -176743,6 +177957,12 @@ SQLITE_API int sqlite3_initialize(void){ } #endif + /* Experimentally determine if high-precision floating point is + ** available. */ +#ifndef SQLITE_OMIT_WSD + sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc); +#endif + return rc; } @@ -177313,6 +178533,10 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ va_list ap; int rc; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); va_start(ap, op); switch( op ){ @@ -177642,6 +178866,14 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){ } #endif + while( db->pDbData ){ + DbClientData *p = db->pDbData; + db->pDbData = p->pNext; + assert( p->pData!=0 ); + if( p->xDestructor ) p->xDestructor(p->pData); + sqlite3_free(p); + } + /* Convert the connection into a zombie and then close it. */ db->eOpenState = SQLITE_STATE_ZOMBIE; @@ -178259,7 +179491,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc( assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY ); extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY| - SQLITE_SUBTYPE|SQLITE_INNOCUOUS); + SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE); enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY); /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But @@ -178716,6 +179948,12 @@ SQLITE_API void *sqlite3_preupdate_hook( void *pArg /* First callback argument */ ){ void *pRet; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( db==0 ){ + return 0; + } +#endif sqlite3_mutex_enter(db->mutex); pRet = db->pPreUpdateArg; db->xPreUpdateCallback = xCallback; @@ -178862,7 +180100,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint ** mode: */ - return SQLITE_MISUSE; + return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); @@ -180099,6 +181337,69 @@ SQLITE_API int sqlite3_collation_needed16( } #endif /* SQLITE_OMIT_UTF16 */ +/* +** Find existing client data. +*/ +SQLITE_API void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){ + DbClientData *p; + sqlite3_mutex_enter(db->mutex); + for(p=db->pDbData; p; p=p->pNext){ + if( strcmp(p->zName, zName)==0 ){ + void *pResult = p->pData; + sqlite3_mutex_leave(db->mutex); + return pResult; + } + } + sqlite3_mutex_leave(db->mutex); + return 0; +} + +/* +** Add new client data to a database connection. +*/ +SQLITE_API int sqlite3_set_clientdata( + sqlite3 *db, /* Attach client data to this connection */ + const char *zName, /* Name of the client data */ + void *pData, /* The client data itself */ + void (*xDestructor)(void*) /* Destructor */ +){ + DbClientData *p, **pp; + sqlite3_mutex_enter(db->mutex); + pp = &db->pDbData; + for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){ + pp = &p->pNext; + } + if( p ){ + assert( p->pData!=0 ); + if( p->xDestructor ) p->xDestructor(p->pData); + if( pData==0 ){ + *pp = p->pNext; + sqlite3_free(p); + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; + } + }else if( pData==0 ){ + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; + }else{ + size_t n = strlen(zName); + p = sqlite3_malloc64( sizeof(DbClientData)+n+1 ); + if( p==0 ){ + if( xDestructor ) xDestructor(pData); + sqlite3_mutex_leave(db->mutex); + return SQLITE_NOMEM; + } + memcpy(p->zName, zName, n+1); + p->pNext = db->pDbData; + db->pDbData = p; + } + p->pData = pData; + p->xDestructor = xDestructor; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + + #ifndef SQLITE_OMIT_DEPRECATED /* ** This function is now an anachronism. It used to be used to recover from a @@ -180448,6 +181749,28 @@ SQLITE_API int sqlite3_test_control(int op, ...){ } #endif + /* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b); + ** + ** If b is true, then activate the SQLITE_FkNoAction setting. If b is + ** false then clearn that setting. If the SQLITE_FkNoAction setting is + ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if + ** they were NO ACTION, regardless of how they are defined. + ** + ** NB: One must usually run "PRAGMA writable_schema=RESET" after + ** using this test-control, before it will take full effect. failing + ** to reset the schema can result in some unexpected behavior. + */ + case SQLITE_TESTCTRL_FK_NO_ACTION: { + sqlite3 *db = va_arg(ap, sqlite3*); + int b = va_arg(ap, int); + if( b ){ + db->flags |= SQLITE_FkNoAction; + }else{ + db->flags &= ~SQLITE_FkNoAction; + } + break; + } + /* ** sqlite3_test_control(BITVEC_TEST, size, program) ** @@ -180872,11 +182195,11 @@ SQLITE_API int sqlite3_test_control(int op, ...){ ** X<0 Make no changes to the bUseLongDouble. Just report value. ** X==0 Disable bUseLongDouble ** X==1 Enable bUseLongDouble - ** X==2 Set bUseLongDouble to its default value for this platform + ** X>=2 Set bUseLongDouble to its default value for this platform */ case SQLITE_TESTCTRL_USELONGDOUBLE: { int b = va_arg(ap, int); - if( b==2 ) b = sizeof(LONGDOUBLE_TYPE)>8; + if( b>=2 ) b = hasHighPrecisionDouble(b); if( b>=0 ) sqlite3Config.bUseLongDouble = b>0; rc = sqlite3Config.bUseLongDouble!=0; break; @@ -181290,7 +182613,7 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){ int nOpt; const char **azCompileOpt; -#if SQLITE_ENABLE_API_ARMOR +#ifdef SQLITE_ENABLE_API_ARMOR if( zOptName==0 ){ (void)SQLITE_MISUSE_BKPT; return 0; @@ -181485,6 +182808,9 @@ SQLITE_API int sqlite3_unlock_notify( ){ int rc = SQLITE_OK; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); enterMutex(); @@ -182506,6 +183832,7 @@ struct Fts3Table { int nPgsz; /* Page size for host database */ char *zSegmentsTbl; /* Name of %_segments table */ sqlite3_blob *pSegments; /* Blob handle open on %_segments table */ + int iSavepoint; /* ** The following array of hash tables is used to buffer pending index @@ -183249,6 +184576,7 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){ zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid"); sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + sqlite3_vtab_config(p->db, SQLITE_VTAB_INNOCUOUS); /* Create a list of user columns for the virtual table */ zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]); @@ -186498,6 +187826,8 @@ static int fts3RenameMethod( rc = sqlite3Fts3PendingTermsFlush(p); } + p->bIgnoreSavepoint = 1; + if( p->zContentTbl==0 ){ fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", @@ -186525,6 +187855,8 @@ static int fts3RenameMethod( "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", p->zDb, p->zName, zName ); + + p->bIgnoreSavepoint = 0; return rc; } @@ -186535,12 +187867,28 @@ static int fts3RenameMethod( */ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ int rc = SQLITE_OK; - UNUSED_PARAMETER(iSavepoint); - assert( ((Fts3Table *)pVtab)->inTransaction ); - assert( ((Fts3Table *)pVtab)->mxSavepoint <= iSavepoint ); - TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint ); - if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){ - rc = fts3SyncMethod(pVtab); + Fts3Table *pTab = (Fts3Table*)pVtab; + assert( pTab->inTransaction ); + assert( pTab->mxSavepoint<=iSavepoint ); + TESTONLY( pTab->mxSavepoint = iSavepoint ); + + if( pTab->bIgnoreSavepoint==0 ){ + if( fts3HashCount(&pTab->aIndex[0].hPending)>0 ){ + char *zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')", + pTab->zDb, pTab->zName, pTab->zName + ); + if( zSql ){ + pTab->bIgnoreSavepoint = 1; + rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0); + pTab->bIgnoreSavepoint = 0; + sqlite3_free(zSql); + }else{ + rc = SQLITE_NOMEM; + } + } + if( rc==SQLITE_OK ){ + pTab->iSavepoint = iSavepoint+1; + } } return rc; } @@ -186551,12 +187899,11 @@ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ ** This is a no-op. */ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ - TESTONLY( Fts3Table *p = (Fts3Table*)pVtab ); - UNUSED_PARAMETER(iSavepoint); - UNUSED_PARAMETER(pVtab); - assert( p->inTransaction ); - assert( p->mxSavepoint >= iSavepoint ); - TESTONLY( p->mxSavepoint = iSavepoint-1 ); + Fts3Table *pTab = (Fts3Table*)pVtab; + assert( pTab->inTransaction ); + assert( pTab->mxSavepoint >= iSavepoint ); + TESTONLY( pTab->mxSavepoint = iSavepoint-1 ); + pTab->iSavepoint = iSavepoint; return SQLITE_OK; } @@ -186566,11 +187913,13 @@ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ ** Discard the contents of the pending terms table. */ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts3Table *p = (Fts3Table*)pVtab; + Fts3Table *pTab = (Fts3Table*)pVtab; UNUSED_PARAMETER(iSavepoint); - assert( p->inTransaction ); - TESTONLY( p->mxSavepoint = iSavepoint ); - sqlite3Fts3PendingTermsClear(p); + assert( pTab->inTransaction ); + TESTONLY( pTab->mxSavepoint = iSavepoint ); + if( (iSavepoint+1)<=pTab->iSavepoint ){ + sqlite3Fts3PendingTermsClear(pTab); + } return SQLITE_OK; } @@ -186589,8 +187938,49 @@ static int fts3ShadowName(const char *zName){ return 0; } +/* +** Implementation of the xIntegrity() method on the FTS3/FTS4 virtual +** table. +*/ +static int fts3Integrity( + sqlite3_vtab *pVtab, /* The virtual table to be checked */ + const char *zSchema, /* Name of schema in which pVtab lives */ + const char *zTabname, /* Name of the pVTab table */ + int isQuick, /* True if this is a quick_check */ + char **pzErr /* Write error message here */ +){ + Fts3Table *p = (Fts3Table*)pVtab; + char *zSql; + int rc; + char *zErr = 0; + + assert( pzErr!=0 ); + assert( *pzErr==0 ); + UNUSED_PARAMETER(isQuick); + zSql = sqlite3_mprintf( + "INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');", + zSchema, zTabname, zTabname); + if( zSql==0 ){ + return SQLITE_NOMEM; + } + rc = sqlite3_exec(p->db, zSql, 0, 0, &zErr); + sqlite3_free(zSql); + if( (rc&0xff)==SQLITE_CORRUPT ){ + *pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s", + p->bFts4 ? 4 : 3, zSchema, zTabname); + }else if( rc!=SQLITE_OK ){ + *pzErr = sqlite3_mprintf("unable to validate the inverted index for" + " FTS%d table %s.%s: %s", + p->bFts4 ? 4 : 3, zSchema, zTabname, zErr); + } + sqlite3_free(zErr); + return SQLITE_OK; +} + + + static const sqlite3_module fts3Module = { - /* iVersion */ 3, + /* iVersion */ 4, /* xCreate */ fts3CreateMethod, /* xConnect */ fts3ConnectMethod, /* xBestIndex */ fts3BestIndexMethod, @@ -186614,6 +188004,7 @@ static const sqlite3_module fts3Module = { /* xRelease */ fts3ReleaseMethod, /* xRollbackTo */ fts3RollbackToMethod, /* xShadowName */ fts3ShadowName, + /* xIntegrity */ fts3Integrity, }; /* @@ -189289,7 +190680,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0 /* xShadowName */ + 0, /* xShadowName */ + 0 /* xIntegrity */ }; int rc; /* Return code */ @@ -192855,7 +194247,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash, void(*xDestr 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0 /* xShadowName */ + 0, /* xShadowName */ + 0 /* xIntegrity */ }; int rc; /* Return code */ @@ -196196,7 +197589,6 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING); if( rc==SQLITE_DONE ) rc = SQLITE_OK; } - sqlite3Fts3PendingTermsClear(p); /* Determine the auto-incr-merge setting if unknown. If enabled, ** estimate the number of leaf blocks of content to be written @@ -196218,6 +197610,10 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ rc = sqlite3_reset(pStmt); } } + + if( rc==SQLITE_OK ){ + sqlite3Fts3PendingTermsClear(p); + } return rc; } @@ -196849,6 +198245,8 @@ static int fts3AppendToNode( blobGrowBuffer(pPrev, nTerm, &rc); if( rc!=SQLITE_OK ) return rc; + assert( pPrev!=0 ); + assert( pPrev->a!=0 ); nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm); nSuffix = nTerm - nPrefix; @@ -196905,9 +198303,13 @@ static int fts3IncrmergeAppend( nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; /* If the current block is not empty, and if adding this term/doclist - ** to the current block would make it larger than Fts3Table.nNodeSize - ** bytes, write this block out to the database. */ - if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize ){ + ** to the current block would make it larger than Fts3Table.nNodeSize bytes, + ** and if there is still room for another leaf page, write this block out to + ** the database. */ + if( pLeaf->block.n>0 + && (pLeaf->block.n + nSpace)>p->nNodeSize + && pLeaf->iBlock < (pWriter->iStart + pWriter->nLeafEst) + ){ rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n); pWriter->nWork++; @@ -197239,7 +198641,7 @@ static int fts3IncrmergeLoad( rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock,0); blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc - ); + ); if( rc==SQLITE_OK ){ memcpy(pNode->block.a, aBlock, nBlock); pNode->block.n = nBlock; @@ -198304,8 +199706,11 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ rc = fts3DoIncrmerge(p, &zVal[6]); }else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){ rc = fts3DoAutoincrmerge(p, &zVal[10]); + }else if( nVal==5 && 0==sqlite3_strnicmp(zVal, "flush", 5) ){ + rc = sqlite3Fts3PendingTermsFlush(p); + } #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - }else{ + else{ int v; if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ v = atoi(&zVal[9]); @@ -198323,8 +199728,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v; rc = SQLITE_OK; } -#endif } +#endif return rc; } @@ -201667,13 +203072,19 @@ static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){ zIn++; N -= 2; while( N>0 ){ - for(i=0; i0 ){ jsonAppendRawNZ(p, zIn, i); zIn += i; N -= i; if( N==0 ) break; } + if( zIn[0]=='"' ){ + jsonAppendRawNZ(p, "\\\"", 2); + zIn++; + N--; + continue; + } assert( zIn[0]=='\\' ); switch( (u8)zIn[1] ){ case '\'': @@ -201837,7 +203248,7 @@ static void jsonResult(JsonString *p){ }else if( jsonForceRCStr(p) ){ sqlite3RCStrRef(p->zBuf); sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, - (void(*)(void*))sqlite3RCStrUnref, + sqlite3RCStrUnref, SQLITE_UTF8); } } @@ -202068,7 +203479,8 @@ static void jsonReturnJson( JsonParse *pParse, /* The complete JSON */ JsonNode *pNode, /* Node to return */ sqlite3_context *pCtx, /* Return value for this function */ - int bGenerateAlt /* Also store the rendered text in zAlt */ + int bGenerateAlt, /* Also store the rendered text in zAlt */ + int omitSubtype /* Do not call sqlite3_result_subtype() */ ){ JsonString s; if( pParse->oom ){ @@ -202083,7 +203495,7 @@ static void jsonReturnJson( pParse->nAlt = s.nUsed; } jsonResult(&s); - sqlite3_result_subtype(pCtx, JSON_SUBTYPE); + if( !omitSubtype ) sqlite3_result_subtype(pCtx, JSON_SUBTYPE); } } @@ -202124,7 +203536,8 @@ static u32 jsonHexToInt4(const char *z){ static void jsonReturn( JsonParse *pParse, /* Complete JSON parse tree */ JsonNode *pNode, /* Node to return */ - sqlite3_context *pCtx /* Return value for this function */ + sqlite3_context *pCtx, /* Return value for this function */ + int omitSubtype /* Do not call sqlite3_result_subtype() */ ){ switch( pNode->eType ){ default: { @@ -202270,7 +203683,7 @@ static void jsonReturn( } case JSON_ARRAY: case JSON_OBJECT: { - jsonReturnJson(pParse, pNode, pCtx, 0); + jsonReturnJson(pParse, pNode, pCtx, 0, omitSubtype); break; } } @@ -203177,7 +204590,7 @@ static JsonParse *jsonParseCached( /* The input JSON was not found anywhere in the cache. We will need ** to parse it ourselves and generate a new JsonParse object. */ - bJsonRCStr = sqlite3ValueIsOfClass(pJson,(void(*)(void*))sqlite3RCStrUnref); + bJsonRCStr = sqlite3ValueIsOfClass(pJson,sqlite3RCStrUnref); p = sqlite3_malloc64( sizeof(*p) + (bJsonRCStr ? 0 : nJson+1) ); if( p==0 ){ sqlite3_result_error_nomem(pCtx); @@ -203391,6 +204804,7 @@ static JsonNode *jsonLookupStep( if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i--; j += jsonNodeSize(&pRoot[j]); } + if( i==0 && j<=pRoot->n ) break; if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; if( pParse->useMod==0 ) break; assert( pRoot->eU==2 ); @@ -203621,7 +205035,7 @@ static void jsonParseFunc( printf("iSubst = %u\n", p->iSubst); printf("iHold = %u\n", p->iHold); jsonDebugPrintNodeEntries(p->aNode, p->nNode); - jsonReturnJson(p, p->aNode, ctx, 1); + jsonReturnJson(p, p->aNode, ctx, 1, 0); } /* @@ -203807,15 +205221,14 @@ static void jsonExtractFunc( } if( pNode ){ if( flags & JSON_JSON ){ - jsonReturnJson(p, pNode, ctx, 0); + jsonReturnJson(p, pNode, ctx, 0, 0); }else{ - jsonReturn(p, pNode, ctx); - sqlite3_result_subtype(ctx, 0); + jsonReturn(p, pNode, ctx, 1); } } }else{ pNode = jsonLookup(p, zPath, 0, ctx); - if( p->nErr==0 && pNode ) jsonReturn(p, pNode, ctx); + if( p->nErr==0 && pNode ) jsonReturn(p, pNode, ctx, 0); } }else{ /* Two or more PATH arguments results in a JSON array with each @@ -203941,7 +205354,7 @@ static void jsonPatchFunc( if( pResult && pX->oom==0 ){ jsonDebugPrintParse(pX); jsonDebugPrintNode(pResult); - jsonReturnJson(pX, pResult, ctx, 0); + jsonReturnJson(pX, pResult, ctx, 0, 0); }else{ sqlite3_result_error_nomem(ctx); } @@ -204020,7 +205433,7 @@ static void jsonRemoveFunc( } } if( (pParse->aNode[0].jnFlags & JNODE_REMOVE)==0 ){ - jsonReturnJson(pParse, pParse->aNode, ctx, 1); + jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0); } remove_done: jsonDebugPrintParse(p); @@ -204078,11 +205491,13 @@ static void jsonReplaceNode( break; } if( sqlite3_value_subtype(pValue)!=JSON_SUBTYPE ){ - char *zCopy = sqlite3DbStrDup(0, z); + char *zCopy = sqlite3_malloc64( n+1 ); int k; if( zCopy ){ + memcpy(zCopy, z, n); + zCopy[n] = 0; jsonParseAddCleanup(p, sqlite3_free, zCopy); - }else{ + }else{ p->oom = 1; sqlite3_result_error_nomem(pCtx); } @@ -204147,7 +205562,7 @@ static void jsonReplaceFunc( jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]); } } - jsonReturnJson(pParse, pParse->aNode, ctx, 1); + jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0); replace_err: jsonDebugPrintParse(pParse); jsonParseFree(pParse); @@ -204201,7 +205616,7 @@ static void jsonSetFunc( } } jsonDebugPrintParse(pParse); - jsonReturnJson(pParse, pParse->aNode, ctx, 1); + jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0); jsonSetDone: jsonParseFree(pParse); } @@ -204359,7 +205774,7 @@ static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : - (void(*)(void*))sqlite3RCStrUnref); + sqlite3RCStrUnref); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); @@ -204468,7 +205883,7 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : - (void(*)(void*))sqlite3RCStrUnref); + sqlite3RCStrUnref); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); @@ -204716,7 +206131,7 @@ static int jsonEachColumn( case JEACH_KEY: { if( p->i==0 ) break; if( p->eType==JSON_OBJECT ){ - jsonReturn(&p->sParse, pThis, ctx); + jsonReturn(&p->sParse, pThis, ctx, 0); }else if( p->eType==JSON_ARRAY ){ u32 iKey; if( p->bRecursive ){ @@ -204732,7 +206147,7 @@ static int jsonEachColumn( } case JEACH_VALUE: { if( pThis->jnFlags & JNODE_LABEL ) pThis++; - jsonReturn(&p->sParse, pThis, ctx); + jsonReturn(&p->sParse, pThis, ctx, 0); break; } case JEACH_TYPE: { @@ -204743,7 +206158,7 @@ static int jsonEachColumn( case JEACH_ATOM: { if( pThis->jnFlags & JNODE_LABEL ) pThis++; if( pThis->eType>=JSON_ARRAY ) break; - jsonReturn(&p->sParse, pThis, ctx); + jsonReturn(&p->sParse, pThis, ctx, 0); break; } case JEACH_ID: { @@ -204900,7 +206315,7 @@ static int jsonEachFilter( if( z==0 ) return SQLITE_OK; memset(&p->sParse, 0, sizeof(p->sParse)); p->sParse.nJPRef = 1; - if( sqlite3ValueIsOfClass(argv[0], (void(*)(void*))sqlite3RCStrUnref) ){ + if( sqlite3ValueIsOfClass(argv[0], sqlite3RCStrUnref) ){ p->sParse.zJson = sqlite3RCStrRef((char*)z); }else{ n = sqlite3_value_bytes(argv[0]); @@ -204995,7 +206410,8 @@ static sqlite3_module jsonEachModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0 /* xShadowName */ + 0, /* xShadowName */ + 0 /* xIntegrity */ }; /* The methods of the json_tree virtual table. */ @@ -205023,7 +206439,8 @@ static sqlite3_module jsonTreeModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0 /* xShadowName */ + 0, /* xShadowName */ + 0 /* xIntegrity */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* !defined(SQLITE_OMIT_JSON) */ @@ -205034,34 +206451,43 @@ static sqlite3_module jsonTreeModule = { SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){ #ifndef SQLITE_OMIT_JSON static FuncDef aJsonFunc[] = { - JFUNCTION(json, 1, 0, jsonRemoveFunc), - JFUNCTION(json_array, -1, 0, jsonArrayFunc), - JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc), - JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc), - JFUNCTION(json_error_position,1, 0, jsonErrorFunc), - JFUNCTION(json_extract, -1, 0, jsonExtractFunc), - JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc), - JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc), - JFUNCTION(json_insert, -1, 0, jsonSetFunc), - JFUNCTION(json_object, -1, 0, jsonObjectFunc), - JFUNCTION(json_patch, 2, 0, jsonPatchFunc), - JFUNCTION(json_quote, 1, 0, jsonQuoteFunc), - JFUNCTION(json_remove, -1, 0, jsonRemoveFunc), - JFUNCTION(json_replace, -1, 0, jsonReplaceFunc), - JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc), - JFUNCTION(json_type, 1, 0, jsonTypeFunc), - JFUNCTION(json_type, 2, 0, jsonTypeFunc), - JFUNCTION(json_valid, 1, 0, jsonValidFunc), -#if SQLITE_DEBUG - JFUNCTION(json_parse, 1, 0, jsonParseFunc), - JFUNCTION(json_test1, 1, 0, jsonTest1Func), + /* calls sqlite3_result_subtype() */ + /* | */ + /* Uses cache ______ | __ calls sqlite3_value_subtype() */ + /* | | | */ + /* Num args _________ | | | ___ Flags */ + /* | | | | | */ + /* | | | | | */ + JFUNCTION(json, 1, 1, 1, 0, 0, jsonRemoveFunc), + JFUNCTION(json_array, -1, 0, 1, 1, 0, jsonArrayFunc), + JFUNCTION(json_array_length, 1, 1, 0, 0, 0, jsonArrayLengthFunc), + JFUNCTION(json_array_length, 2, 1, 0, 0, 0, jsonArrayLengthFunc), + JFUNCTION(json_error_position,1, 1, 0, 0, 0, jsonErrorFunc), + JFUNCTION(json_extract, -1, 1, 1, 0, 0, jsonExtractFunc), + JFUNCTION(->, 2, 1, 1, 0, JSON_JSON, jsonExtractFunc), + JFUNCTION(->>, 2, 1, 0, 0, JSON_SQL, jsonExtractFunc), + JFUNCTION(json_insert, -1, 1, 1, 1, 0, jsonSetFunc), + JFUNCTION(json_object, -1, 0, 1, 1, 0, jsonObjectFunc), + JFUNCTION(json_patch, 2, 1, 1, 0, 0, jsonPatchFunc), + JFUNCTION(json_quote, 1, 0, 1, 1, 0, jsonQuoteFunc), + JFUNCTION(json_remove, -1, 1, 1, 0, 0, jsonRemoveFunc), + JFUNCTION(json_replace, -1, 1, 1, 1, 0, jsonReplaceFunc), + JFUNCTION(json_set, -1, 1, 1, 1, JSON_ISSET, jsonSetFunc), + JFUNCTION(json_type, 1, 1, 0, 0, 0, jsonTypeFunc), + JFUNCTION(json_type, 2, 1, 0, 0, 0, jsonTypeFunc), + JFUNCTION(json_valid, 1, 1, 0, 0, 0, jsonValidFunc), +#ifdef SQLITE_DEBUG + JFUNCTION(json_parse, 1, 1, 1, 0, 0, jsonParseFunc), + JFUNCTION(json_test1, 1, 1, 0, 1, 0, jsonTest1Func), #endif WAGGREGATE(json_group_array, 1, 0, 0, jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, - SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC), + SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| + SQLITE_DETERMINISTIC), WAGGREGATE(json_group_object, 2, 0, 0, jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, - SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC) + SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| + SQLITE_DETERMINISTIC) }; sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc)); #endif @@ -205258,6 +206684,7 @@ struct Rtree { int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ + char *zNodeName; /* Name of the %_node table */ u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ u32 nCursor; /* Number of open cursors */ @@ -205270,7 +206697,6 @@ struct Rtree { ** headed by the node (leaf nodes have RtreeNode.iNode==0). */ RtreeNode *pDeleted; - int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */ /* Blob I/O on xxx_node */ sqlite3_blob *pNodeBlob; @@ -205567,15 +206993,20 @@ struct RtreeMatchArg { ** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined ** at run-time. */ -#ifndef SQLITE_BYTEORDER -# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ +#ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */ +# if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ +# define SQLITE_BYTEORDER 4321 +# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ +# define SQLITE_BYTEORDER 1234 +# elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1 +# define SQLITE_BYTEORDER 4321 +# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64) -# define SQLITE_BYTEORDER 1234 -# elif defined(sparc) || defined(__ppc__) || \ - defined(__ARMEB__) || defined(__AARCH64EB__) -# define SQLITE_BYTEORDER 4321 +# define SQLITE_BYTEORDER 1234 +# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__) +# define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 # endif @@ -205824,11 +207255,9 @@ static int nodeAcquire( } } if( pRtree->pNodeBlob==0 ){ - char *zTab = sqlite3_mprintf("%s_node", pRtree->zName); - if( zTab==0 ) return SQLITE_NOMEM; - rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0, + rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, pRtree->zNodeName, + "data", iNode, 0, &pRtree->pNodeBlob); - sqlite3_free(zTab); } if( rc ){ nodeBlobReset(pRtree); @@ -207169,8 +208598,12 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ pIdxInfo->idxNum = 2; pIdxInfo->needToFreeIdxStr = 1; - if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){ - return SQLITE_NOMEM; + if( iIdx>0 ){ + pIdxInfo->idxStr = sqlite3_malloc( iIdx+1 ); + if( pIdxInfo->idxStr==0 ){ + return SQLITE_NOMEM; + } + memcpy(pIdxInfo->idxStr, zIdxStr, iIdx+1); } nRow = pRtree->nRowEst >> (iIdx/2); @@ -207249,31 +208682,22 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ */ static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ int ii; - int isInt = (pRtree->eCoordType==RTREE_COORD_INT32); - for(ii=0; iinDim2; ii+=2){ - RtreeCoord *a1 = &p1->aCoord[ii]; - RtreeCoord *a2 = &p2->aCoord[ii]; - if( (!isInt && (a2[0].fa1[1].f)) - || ( isInt && (a2[0].ia1[1].i)) - ){ - return 0; + if( pRtree->eCoordType==RTREE_COORD_INT32 ){ + for(ii=0; iinDim2; ii+=2){ + RtreeCoord *a1 = &p1->aCoord[ii]; + RtreeCoord *a2 = &p2->aCoord[ii]; + if( a2[0].ia1[1].i ) return 0; + } + }else{ + for(ii=0; iinDim2; ii+=2){ + RtreeCoord *a1 = &p1->aCoord[ii]; + RtreeCoord *a2 = &p2->aCoord[ii]; + if( a2[0].fa1[1].f ) return 0; } } return 1; } -/* -** Return the amount cell p would grow by if it were unioned with pCell. -*/ -static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ - RtreeDValue area; - RtreeCell cell; - memcpy(&cell, p, sizeof(RtreeCell)); - area = cellArea(pRtree, &cell); - cellUnion(pRtree, &cell, pCell); - return (cellArea(pRtree, &cell)-area); -} - static RtreeDValue cellOverlap( Rtree *pRtree, RtreeCell *p, @@ -207320,38 +208744,52 @@ static int ChooseLeaf( for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){ int iCell; sqlite3_int64 iBest = 0; - + int bFound = 0; RtreeDValue fMinGrowth = RTREE_ZERO; RtreeDValue fMinArea = RTREE_ZERO; - int nCell = NCELL(pNode); - RtreeCell cell; RtreeNode *pChild = 0; - RtreeCell *aCell = 0; - - /* Select the child node which will be enlarged the least if pCell - ** is inserted into it. Resolve ties by choosing the entry with - ** the smallest area. + /* First check to see if there is are any cells in pNode that completely + ** contains pCell. If two or more cells in pNode completely contain pCell + ** then pick the smallest. */ for(iCell=0; iCell1 ){ - int iLeft = 0; - int iRight = 0; - - int nLeft = nIdx/2; - int nRight = nIdx-nLeft; - int *aLeft = aIdx; - int *aRight = &aIdx[nLeft]; - - SortByDistance(aLeft, nLeft, aDistance, aSpare); - SortByDistance(aRight, nRight, aDistance, aSpare); - - memcpy(aSpare, aLeft, sizeof(int)*nLeft); - aLeft = aSpare; - - while( iLeftnDim; iDim++){ - aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]); - aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]); - } - } - for(iDim=0; iDimnDim; iDim++){ - aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2)); - } - - for(ii=0; iinDim; iDim++){ - RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - - DCOORD(aCell[ii].aCoord[iDim*2])); - aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]); - } - } - - SortByDistance(aOrder, nCell, aDistance, aSpare); - nodeZero(pRtree, pNode); - - for(ii=0; rc==SQLITE_OK && ii<(nCell-(RTREE_MINCELLS(pRtree)+1)); ii++){ - RtreeCell *p = &aCell[aOrder[ii]]; - nodeInsertCell(pRtree, pNode, p); - if( p->iRowid==pCell->iRowid ){ - if( iHeight==0 ){ - rc = rowidWrite(pRtree, p->iRowid, pNode->iNode); - }else{ - rc = parentWrite(pRtree, p->iRowid, pNode->iNode); - } - } - } - if( rc==SQLITE_OK ){ - rc = fixBoundingBox(pRtree, pNode); - } - for(; rc==SQLITE_OK && iiiNode currently contains - ** the height of the sub-tree headed by the cell. - */ - RtreeNode *pInsert; - RtreeCell *p = &aCell[aOrder[ii]]; - rc = ChooseLeaf(pRtree, p, iHeight, &pInsert); - if( rc==SQLITE_OK ){ - int rc2; - rc = rtreeInsertCell(pRtree, pInsert, p, iHeight); - rc2 = nodeRelease(pRtree, pInsert); - if( rc==SQLITE_OK ){ - rc = rc2; - } - } - } - - sqlite3_free(aCell); - return rc; -} - /* ** Insert cell pCell into node pNode. Node pNode is the head of a ** subtree iHeight high (leaf nodes have iHeight==0). @@ -208100,12 +209366,7 @@ static int rtreeInsertCell( } } if( nodeInsertCell(pRtree, pNode, pCell) ){ - if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){ - rc = SplitNode(pRtree, pNode, pCell, iHeight); - }else{ - pRtree->iReinsertHeight = iHeight; - rc = Reinsert(pRtree, pNode, pCell, iHeight); - } + rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ rc = AdjustTree(pRtree, pNode, pCell); if( ALWAYS(rc==SQLITE_OK) ){ @@ -208448,7 +209709,6 @@ static int rtreeUpdate( } if( rc==SQLITE_OK ){ int rc2; - pRtree->iReinsertHeight = -1; rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ @@ -208589,8 +209849,11 @@ static int rtreeShadowName(const char *zName){ return 0; } +/* Forward declaration */ +static int rtreeIntegrity(sqlite3_vtab*, const char*, const char*, int, char**); + static sqlite3_module rtreeModule = { - 3, /* iVersion */ + 4, /* iVersion */ rtreeCreate, /* xCreate - create a table */ rtreeConnect, /* xConnect - connect to an existing table */ rtreeBestIndex, /* xBestIndex - Determine search strategy */ @@ -208613,7 +209876,8 @@ static sqlite3_module rtreeModule = { rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - rtreeShadowName /* xShadowName */ + rtreeShadowName, /* xShadowName */ + rtreeIntegrity /* xIntegrity */ }; static int rtreeSqlInit( @@ -208869,22 +210133,27 @@ static int rtreeInit( } sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); + /* Allocate the sqlite3_vtab structure */ nDb = (int)strlen(argv[1]); nName = (int)strlen(argv[2]); - pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); + pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8); if( !pRtree ){ return SQLITE_NOMEM; } - memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); + memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8); pRtree->nBusy = 1; pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; pRtree->zName = &pRtree->zDb[nDb+1]; + pRtree->zNodeName = &pRtree->zName[nName+1]; pRtree->eCoordType = (u8)eCoordType; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); + memcpy(pRtree->zNodeName, argv[2], nName); + memcpy(&pRtree->zNodeName[nName], "_node", 6); /* Create/Connect to the underlying relational database schema. If @@ -209381,7 +210650,6 @@ static int rtreeCheckTable( ){ RtreeCheck check; /* Common context for various routines */ sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */ - int bEnd = 0; /* True if transaction should be closed */ int nAux = 0; /* Number of extra columns. */ /* Initialize the context object */ @@ -209390,14 +210658,6 @@ static int rtreeCheckTable( check.zDb = zDb; check.zTab = zTab; - /* If there is not already an open transaction, open one now. This is - ** to ensure that the queries run as part of this integrity-check operate - ** on a consistent snapshot. */ - if( sqlite3_get_autocommit(db) ){ - check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0); - bEnd = 1; - } - /* Find the number of auxiliary columns */ if( check.rc==SQLITE_OK ){ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab); @@ -209438,15 +210698,34 @@ static int rtreeCheckTable( sqlite3_finalize(check.aCheckMapping[0]); sqlite3_finalize(check.aCheckMapping[1]); - /* If one was opened, close the transaction */ - if( bEnd ){ - int rc = sqlite3_exec(db, "END", 0, 0, 0); - if( check.rc==SQLITE_OK ) check.rc = rc; - } *pzReport = check.zReport; return check.rc; } +/* +** Implementation of the xIntegrity method for Rtree. +*/ +static int rtreeIntegrity( + sqlite3_vtab *pVtab, /* The virtual table to check */ + const char *zSchema, /* Schema in which the virtual table lives */ + const char *zName, /* Name of the virtual table */ + int isQuick, /* True for a quick_check */ + char **pzErr /* Write results here */ +){ + Rtree *pRtree = (Rtree*)pVtab; + int rc; + assert( pzErr!=0 && *pzErr==0 ); + UNUSED_PARAMETER(zSchema); + UNUSED_PARAMETER(zName); + UNUSED_PARAMETER(isQuick); + rc = rtreeCheckTable(pRtree->db, pRtree->zDb, pRtree->zName, pzErr); + if( rc==SQLITE_OK && *pzErr ){ + *pzErr = sqlite3_mprintf("In RTree %s.%s:\n%z", + pRtree->zDb, pRtree->zName, *pzErr); + } + return rc; +} + /* ** Usage: ** @@ -210768,24 +212047,28 @@ static int geopolyInit( (void)pAux; sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); /* Allocate the sqlite3_vtab structure */ nDb = strlen(argv[1]); nName = strlen(argv[2]); - pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); + pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8); if( !pRtree ){ return SQLITE_NOMEM; } - memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); + memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8); pRtree->nBusy = 1; pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; pRtree->zName = &pRtree->zDb[nDb+1]; + pRtree->zNodeName = &pRtree->zName[nName+1]; pRtree->eCoordType = RTREE_COORD_REAL32; pRtree->nDim = 2; pRtree->nDim2 = 4; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); + memcpy(pRtree->zNodeName, argv[2], nName); + memcpy(&pRtree->zNodeName[nName], "_node", 6); /* Create/Connect to the underlying relational database schema. If @@ -211199,7 +212482,6 @@ static int geopolyUpdate( } if( rc==SQLITE_OK ){ int rc2; - pRtree->iReinsertHeight = -1; rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ @@ -211296,7 +212578,8 @@ static sqlite3_module geopolyModule = { rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - rtreeShadowName /* xShadowName */ + rtreeShadowName, /* xShadowName */ + rtreeIntegrity /* xIntegrity */ }; static int sqlite3_geopoly_init(sqlite3 *db){ @@ -219310,7 +220593,8 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0 /* xShadowName */ + 0, /* xShadowName */ + 0 /* xIntegrity */ }; return sqlite3_create_module(db, "dbstat", &dbstat_module, 0); } @@ -219747,7 +221031,8 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0 /* xShadowName */ + 0, /* xShadowName */ + 0 /* xIntegrity */ }; return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); } @@ -219878,6 +221163,18 @@ struct sqlite3_changeset_iter { ** The data associated with each hash-table entry is a structure containing ** a subset of the initial values that the modified row contained at the ** start of the session. Or no initial values if the row was inserted. +** +** pDfltStmt: +** This is only used by the sqlite3changegroup_xxx() APIs, not by +** regular sqlite3_session objects. It is a SELECT statement that +** selects the default value for each table column. For example, +** if the table is +** +** CREATE TABLE xx(a DEFAULT 1, b, c DEFAULT 'abc') +** +** then this variable is the compiled version of: +** +** SELECT 1, NULL, 'abc' */ struct SessionTable { SessionTable *pNext; @@ -219886,10 +221183,12 @@ struct SessionTable { int bStat1; /* True if this is sqlite_stat1 */ int bRowid; /* True if this table uses rowid for PK */ const char **azCol; /* Column names */ + const char **azDflt; /* Default value expressions */ u8 *abPK; /* Array of primary key flags */ int nEntry; /* Total number of entries in hash table */ int nChange; /* Size of apChange[] array */ SessionChange **apChange; /* Hash table buckets */ + sqlite3_stmt *pDfltStmt; }; /* @@ -220058,6 +221357,7 @@ struct SessionTable { struct SessionChange { u8 op; /* One of UPDATE, DELETE, INSERT */ u8 bIndirect; /* True if this change is "indirect" */ + u16 nRecordField; /* Number of fields in aRecord[] */ int nMaxSize; /* Max size of eventual changeset record */ int nRecord; /* Number of bytes in buffer aRecord[] */ u8 *aRecord; /* Buffer containing old.* record */ @@ -220083,7 +221383,7 @@ static int sessionVarintLen(int iVal){ ** Read a varint value from aBuf[] into *piVal. Return the number of ** bytes read. */ -static int sessionVarintGet(u8 *aBuf, int *piVal){ +static int sessionVarintGet(const u8 *aBuf, int *piVal){ return getVarint32(aBuf, *piVal); } @@ -220346,9 +221646,11 @@ static int sessionPreupdateHash( ** Return the number of bytes of space occupied by the value (including ** the type byte). */ -static int sessionSerialLen(u8 *a){ - int e = *a; +static int sessionSerialLen(const u8 *a){ + int e; int n; + assert( a!=0 ); + e = *a; if( e==0 || e==0xFF ) return 1; if( e==SQLITE_NULL ) return 1; if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9; @@ -220753,13 +222055,14 @@ static int sessionGrowHash( ** ** For example, if the table is declared as: ** -** CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z)); +** CREATE TABLE tbl1(w, x DEFAULT 'abc', y, z, PRIMARY KEY(w, z)); ** -** Then the four output variables are populated as follows: +** Then the five output variables are populated as follows: ** ** *pnCol = 4 ** *pzTab = "tbl1" ** *pazCol = {"w", "x", "y", "z"} +** *pazDflt = {NULL, 'abc', NULL, NULL} ** *pabPK = {1, 0, 0, 1} ** ** All returned buffers are part of the same single allocation, which must @@ -220773,6 +222076,7 @@ static int sessionTableInfo( int *pnCol, /* OUT: number of columns */ const char **pzTab, /* OUT: Copy of zThis */ const char ***pazCol, /* OUT: Array of column names for table */ + const char ***pazDflt, /* OUT: Array of default value expressions */ u8 **pabPK, /* OUT: Array of booleans - true for PK col */ int *pbRowid /* OUT: True if only PK is a rowid */ ){ @@ -220785,11 +222089,18 @@ static int sessionTableInfo( int i; u8 *pAlloc = 0; char **azCol = 0; + char **azDflt = 0; u8 *abPK = 0; int bRowid = 0; /* Set to true to use rowid as PK */ assert( pazCol && pabPK ); + *pazCol = 0; + *pabPK = 0; + *pnCol = 0; + if( pzTab ) *pzTab = 0; + if( pazDflt ) *pazDflt = 0; + nThis = sqlite3Strlen30(zThis); if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){ rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0); @@ -220803,39 +222114,28 @@ static int sessionTableInfo( }else if( rc==SQLITE_ERROR ){ zPragma = sqlite3_mprintf(""); }else{ - *pazCol = 0; - *pabPK = 0; - *pnCol = 0; - if( pzTab ) *pzTab = 0; return rc; } }else{ zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); } if( !zPragma ){ - *pazCol = 0; - *pabPK = 0; - *pnCol = 0; - if( pzTab ) *pzTab = 0; return SQLITE_NOMEM; } rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0); sqlite3_free(zPragma); if( rc!=SQLITE_OK ){ - *pazCol = 0; - *pabPK = 0; - *pnCol = 0; - if( pzTab ) *pzTab = 0; return rc; } nByte = nThis + 1; bRowid = (pbRowid!=0); while( SQLITE_ROW==sqlite3_step(pStmt) ){ - nByte += sqlite3_column_bytes(pStmt, 1); + nByte += sqlite3_column_bytes(pStmt, 1); /* name */ + nByte += sqlite3_column_bytes(pStmt, 4); /* dflt_value */ nDbCol++; - if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; + if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */ } if( nDbCol==0 ) bRowid = 0; nDbCol += bRowid; @@ -220843,15 +222143,18 @@ static int sessionTableInfo( rc = sqlite3_reset(pStmt); if( rc==SQLITE_OK ){ - nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1); + nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1); pAlloc = sessionMalloc64(pSession, nByte); if( pAlloc==0 ){ rc = SQLITE_NOMEM; + }else{ + memset(pAlloc, 0, nByte); } } if( rc==SQLITE_OK ){ azCol = (char **)pAlloc; - pAlloc = (u8 *)&azCol[nDbCol]; + azDflt = (char**)&azCol[nDbCol]; + pAlloc = (u8 *)&azDflt[nDbCol]; abPK = (u8 *)pAlloc; pAlloc = &abPK[nDbCol]; if( pzTab ){ @@ -220871,11 +222174,21 @@ static int sessionTableInfo( } while( SQLITE_ROW==sqlite3_step(pStmt) ){ int nName = sqlite3_column_bytes(pStmt, 1); + int nDflt = sqlite3_column_bytes(pStmt, 4); const unsigned char *zName = sqlite3_column_text(pStmt, 1); + const unsigned char *zDflt = sqlite3_column_text(pStmt, 4); + if( zName==0 ) break; memcpy(pAlloc, zName, nName+1); azCol[i] = (char *)pAlloc; pAlloc += nName+1; + if( zDflt ){ + memcpy(pAlloc, zDflt, nDflt+1); + azDflt[i] = (char *)pAlloc; + pAlloc += nDflt+1; + }else{ + azDflt[i] = 0; + } abPK[i] = sqlite3_column_int(pStmt, 5); i++; } @@ -220886,14 +222199,11 @@ static int sessionTableInfo( ** free any allocation made. An error code will be returned in this case. */ if( rc==SQLITE_OK ){ - *pazCol = (const char **)azCol; + *pazCol = (const char**)azCol; + if( pazDflt ) *pazDflt = (const char**)azDflt; *pabPK = abPK; *pnCol = nDbCol; }else{ - *pazCol = 0; - *pabPK = 0; - *pnCol = 0; - if( pzTab ) *pzTab = 0; sessionFree(pSession, azCol); } if( pbRowid ) *pbRowid = bRowid; @@ -220902,10 +222212,9 @@ static int sessionTableInfo( } /* -** This function is only called from within a pre-update handler for a -** write to table pTab, part of session pSession. If this is the first -** write to this table, initalize the SessionTable.nCol, azCol[] and -** abPK[] arrays accordingly. +** This function is called to initialize the SessionTable.nCol, azCol[] +** abPK[] and azDflt[] members of SessionTable object pTab. If these +** fields are already initilialized, this function is a no-op. ** ** If an error occurs, an error code is stored in sqlite3_session.rc and ** non-zero returned. Or, if no error occurs but the table has no primary @@ -220913,15 +222222,22 @@ static int sessionTableInfo( ** indicate that updates on this table should be ignored. SessionTable.abPK ** is set to NULL in this case. */ -static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ +static int sessionInitTable( + sqlite3_session *pSession, /* Optional session handle */ + SessionTable *pTab, /* Table object to initialize */ + sqlite3 *db, /* Database handle to read schema from */ + const char *zDb /* Name of db - "main", "temp" etc. */ +){ + int rc = SQLITE_OK; + if( pTab->nCol==0 ){ u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); - pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb, - pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK, - (pSession->bImplicitPK ? &pTab->bRowid : 0) + rc = sessionTableInfo(pSession, db, zDb, + pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK, + ((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0) ); - if( pSession->rc==SQLITE_OK ){ + if( rc==SQLITE_OK ){ int i; for(i=0; inCol; i++){ if( abPK[i] ){ @@ -220933,14 +222249,321 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ pTab->bStat1 = 1; } - if( pSession->bEnableSize ){ + if( pSession && pSession->bEnableSize ){ pSession->nMaxChangesetSize += ( 1 + sessionVarintLen(pTab->nCol) + pTab->nCol + strlen(pTab->zName)+1 ); } } } - return (pSession->rc || pTab->abPK==0); + + if( pSession ){ + pSession->rc = rc; + return (rc || pTab->abPK==0); + } + return rc; +} + +/* +** Re-initialize table object pTab. +*/ +static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){ + int nCol = 0; + const char **azCol = 0; + const char **azDflt = 0; + u8 *abPK = 0; + int bRowid = 0; + + assert( pSession->rc==SQLITE_OK ); + + pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb, + pTab->zName, &nCol, 0, &azCol, &azDflt, &abPK, + (pSession->bImplicitPK ? &bRowid : 0) + ); + if( pSession->rc==SQLITE_OK ){ + if( pTab->nCol>nCol || pTab->bRowid!=bRowid ){ + pSession->rc = SQLITE_SCHEMA; + }else{ + int ii; + int nOldCol = pTab->nCol; + for(ii=0; iinCol ){ + if( pTab->abPK[ii]!=abPK[ii] ){ + pSession->rc = SQLITE_SCHEMA; + } + }else if( abPK[ii] ){ + pSession->rc = SQLITE_SCHEMA; + } + } + + if( pSession->rc==SQLITE_OK ){ + const char **a = pTab->azCol; + pTab->azCol = azCol; + pTab->nCol = nCol; + pTab->azDflt = azDflt; + pTab->abPK = abPK; + azCol = a; + } + if( pSession->bEnableSize ){ + pSession->nMaxChangesetSize += (nCol - nOldCol); + pSession->nMaxChangesetSize += sessionVarintLen(nCol); + pSession->nMaxChangesetSize -= sessionVarintLen(nOldCol); + } + } + } + + sqlite3_free((char*)azCol); + return pSession->rc; +} + +/* +** Session-change object (*pp) contains an old.* record with fewer than +** nCol fields. This function updates it with the default values for +** the missing fields. +*/ +static void sessionUpdateOneChange( + sqlite3_session *pSession, /* For memory accounting */ + int *pRc, /* IN/OUT: Error code */ + SessionChange **pp, /* IN/OUT: Change object to update */ + int nCol, /* Number of columns now in table */ + sqlite3_stmt *pDflt /* SELECT */ +){ + SessionChange *pOld = *pp; + + while( pOld->nRecordFieldnRecordField; + int eType = sqlite3_column_type(pDflt, iField); + switch( eType ){ + case SQLITE_NULL: + nIncr = 1; + break; + case SQLITE_INTEGER: + case SQLITE_FLOAT: + nIncr = 9; + break; + default: { + int n = sqlite3_column_bytes(pDflt, iField); + nIncr = 1 + sessionVarintLen(n) + n; + assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); + break; + } + } + + nByte = nIncr + (sizeof(SessionChange) + pOld->nRecord); + pNew = sessionMalloc64(pSession, nByte); + if( pNew==0 ){ + *pRc = SQLITE_NOMEM; + return; + }else{ + memcpy(pNew, pOld, sizeof(SessionChange)); + pNew->aRecord = (u8*)&pNew[1]; + memcpy(pNew->aRecord, pOld->aRecord, pOld->nRecord); + pNew->aRecord[pNew->nRecord++] = (u8)eType; + switch( eType ){ + case SQLITE_INTEGER: { + i64 iVal = sqlite3_column_int64(pDflt, iField); + sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal); + pNew->nRecord += 8; + break; + } + + case SQLITE_FLOAT: { + double rVal = sqlite3_column_double(pDflt, iField); + i64 iVal = 0; + memcpy(&iVal, &rVal, sizeof(rVal)); + sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal); + pNew->nRecord += 8; + break; + } + + case SQLITE_TEXT: { + int n = sqlite3_column_bytes(pDflt, iField); + const char *z = (const char*)sqlite3_column_text(pDflt, iField); + pNew->nRecord += sessionVarintPut(&pNew->aRecord[pNew->nRecord], n); + memcpy(&pNew->aRecord[pNew->nRecord], z, n); + pNew->nRecord += n; + break; + } + + case SQLITE_BLOB: { + int n = sqlite3_column_bytes(pDflt, iField); + const u8 *z = (const u8*)sqlite3_column_blob(pDflt, iField); + pNew->nRecord += sessionVarintPut(&pNew->aRecord[pNew->nRecord], n); + memcpy(&pNew->aRecord[pNew->nRecord], z, n); + pNew->nRecord += n; + break; + } + + default: + assert( eType==SQLITE_NULL ); + break; + } + + sessionFree(pSession, pOld); + *pp = pOld = pNew; + pNew->nRecordField++; + pNew->nMaxSize += nIncr; + if( pSession ){ + pSession->nMaxChangesetSize += nIncr; + } + } + } +} + +/* +** Ensure that there is room in the buffer to append nByte bytes of data. +** If not, use sqlite3_realloc() to grow the buffer so that there is. +** +** If successful, return zero. Otherwise, if an OOM condition is encountered, +** set *pRc to SQLITE_NOMEM and return non-zero. +*/ +static int sessionBufferGrow(SessionBuffer *p, i64 nByte, int *pRc){ +#define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1) + i64 nReq = p->nBuf + nByte; + if( *pRc==SQLITE_OK && nReq>p->nAlloc ){ + u8 *aNew; + i64 nNew = p->nAlloc ? p->nAlloc : 128; + + do { + nNew = nNew*2; + }while( nNewSESSION_MAX_BUFFER_SZ ){ + nNew = SESSION_MAX_BUFFER_SZ; + if( nNewaBuf, nNew); + if( 0==aNew ){ + *pRc = SQLITE_NOMEM; + }else{ + p->aBuf = aNew; + p->nAlloc = nNew; + } + } + return (*pRc!=SQLITE_OK); +} + + +/* +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwise, append a string to the buffer. All bytes in the string +** up to (but not including) the nul-terminator are written to the buffer. +** +** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before +** returning. +*/ +static void sessionAppendStr( + SessionBuffer *p, + const char *zStr, + int *pRc +){ + int nStr = sqlite3Strlen30(zStr); + if( 0==sessionBufferGrow(p, nStr+1, pRc) ){ + memcpy(&p->aBuf[p->nBuf], zStr, nStr); + p->nBuf += nStr; + p->aBuf[p->nBuf] = 0x00; + } +} + +/* +** Format a string using printf() style formatting and then append it to the +** buffer using sessionAppendString(). +*/ +static void sessionAppendPrintf( + SessionBuffer *p, /* Buffer to append to */ + int *pRc, + const char *zFmt, + ... +){ + if( *pRc==SQLITE_OK ){ + char *zApp = 0; + va_list ap; + va_start(ap, zFmt); + zApp = sqlite3_vmprintf(zFmt, ap); + if( zApp==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + sessionAppendStr(p, zApp, pRc); + } + va_end(ap); + sqlite3_free(zApp); + } +} + +/* +** Prepare a statement against database handle db that SELECTs a single +** row containing the default values for each column in table pTab. For +** example, if pTab is declared as: +** +** CREATE TABLE pTab(a PRIMARY KEY, b DEFAULT 123, c DEFAULT 'abcd'); +** +** Then this function prepares and returns the SQL statement: +** +** SELECT NULL, 123, 'abcd'; +*/ +static int sessionPrepareDfltStmt( + sqlite3 *db, /* Database handle */ + SessionTable *pTab, /* Table to prepare statement for */ + sqlite3_stmt **ppStmt /* OUT: Statement handle */ +){ + SessionBuffer sql = {0,0,0}; + int rc = SQLITE_OK; + const char *zSep = " "; + int ii = 0; + + *ppStmt = 0; + sessionAppendPrintf(&sql, &rc, "SELECT"); + for(ii=0; iinCol; ii++){ + const char *zDflt = pTab->azDflt[ii] ? pTab->azDflt[ii] : "NULL"; + sessionAppendPrintf(&sql, &rc, "%s%s", zSep, zDflt); + zSep = ", "; + } + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare_v2(db, (const char*)sql.aBuf, -1, ppStmt, 0); + } + sqlite3_free(sql.aBuf); + + return rc; +} + +/* +** Table pTab has one or more existing change-records with old.* records +** with fewer than pTab->nCol columns. This function updates all such +** change-records with the default values for the missing columns. +*/ +static int sessionUpdateChanges(sqlite3_session *pSession, SessionTable *pTab){ + sqlite3_stmt *pStmt = 0; + int rc = pSession->rc; + + rc = sessionPrepareDfltStmt(pSession->db, pTab, &pStmt); + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + int ii = 0; + SessionChange **pp = 0; + for(ii=0; iinChange; ii++){ + for(pp=&pTab->apChange[ii]; *pp; pp=&((*pp)->pNext)){ + if( (*pp)->nRecordField!=pTab->nCol ){ + sessionUpdateOneChange(pSession, &rc, pp, pTab->nCol, pStmt); + } + } + } + } + + pSession->rc = rc; + rc = sqlite3_finalize(pStmt); + if( pSession->rc==SQLITE_OK ) pSession->rc = rc; + return pSession->rc; } /* @@ -221103,16 +222726,22 @@ static void sessionPreupdateOneChange( int iHash; int bNull = 0; int rc = SQLITE_OK; + int nExpect = 0; SessionStat1Ctx stat1 = {{0,0,0,0,0},0}; if( pSession->rc ) return; /* Load table details if required */ - if( sessionInitTable(pSession, pTab) ) return; + if( sessionInitTable(pSession, pTab, pSession->db, pSession->zDb) ) return; /* Check the number of columns in this xPreUpdate call matches the ** number of columns in the table. */ - if( (pTab->nCol-pTab->bRowid)!=pSession->hook.xCount(pSession->hook.pCtx) ){ + nExpect = pSession->hook.xCount(pSession->hook.pCtx); + if( (pTab->nCol-pTab->bRowid)nCol-pTab->bRowid)!=nExpect ){ pSession->rc = SQLITE_SCHEMA; return; } @@ -221189,7 +222818,7 @@ static void sessionPreupdateOneChange( } /* Allocate the change object */ - pC = (SessionChange *)sessionMalloc64(pSession, nByte); + pC = (SessionChange*)sessionMalloc64(pSession, nByte); if( !pC ){ rc = SQLITE_NOMEM; goto error_out; @@ -221222,6 +222851,7 @@ static void sessionPreupdateOneChange( if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){ pC->bIndirect = 1; } + pC->nRecordField = pTab->nCol; pC->nRecord = nByte; pC->op = op; pC->pNext = pTab->apChange[iHash]; @@ -221601,7 +223231,7 @@ SQLITE_API int sqlite3session_diff( /* Locate and if necessary initialize the target table object */ rc = sessionFindTable(pSession, zTbl, &pTo); if( pTo==0 ) goto diff_out; - if( sessionInitTable(pSession, pTo) ){ + if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){ rc = pSession->rc; goto diff_out; } @@ -221614,7 +223244,7 @@ SQLITE_API int sqlite3session_diff( int bRowid = 0; u8 *abPK; const char **azCol = 0; - rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK, + rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, 0, &abPK, pSession->bImplicitPK ? &bRowid : 0 ); if( rc==SQLITE_OK ){ @@ -221729,6 +223359,7 @@ static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){ sessionFree(pSession, p); } } + sqlite3_finalize(pTab->pDfltStmt); sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */ sessionFree(pSession, pTab->apChange); sessionFree(pSession, pTab); @@ -221763,7 +223394,7 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){ /* Assert that all allocations have been freed and then free the ** session object itself. */ - assert( pSession->nMalloc==0 ); + // assert( pSession->nMalloc==0 ); sqlite3_free(pSession); } @@ -221834,48 +223465,6 @@ SQLITE_API int sqlite3session_attach( return rc; } -/* -** Ensure that there is room in the buffer to append nByte bytes of data. -** If not, use sqlite3_realloc() to grow the buffer so that there is. -** -** If successful, return zero. Otherwise, if an OOM condition is encountered, -** set *pRc to SQLITE_NOMEM and return non-zero. -*/ -static int sessionBufferGrow(SessionBuffer *p, i64 nByte, int *pRc){ -#define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1) - i64 nReq = p->nBuf + nByte; - if( *pRc==SQLITE_OK && nReq>p->nAlloc ){ - u8 *aNew; - i64 nNew = p->nAlloc ? p->nAlloc : 128; - - do { - nNew = nNew*2; - }while( nNewSESSION_MAX_BUFFER_SZ ){ - nNew = SESSION_MAX_BUFFER_SZ; - if( nNewaBuf, nNew); - if( 0==aNew ){ - *pRc = SQLITE_NOMEM; - }else{ - p->aBuf = aNew; - p->nAlloc = nNew; - } - } - return (*pRc!=SQLITE_OK); -} - /* ** Append the value passed as the second argument to the buffer passed ** as the first. @@ -221944,27 +223533,6 @@ static void sessionAppendBlob( } } -/* -** This function is a no-op if *pRc is other than SQLITE_OK when it is -** called. Otherwise, append a string to the buffer. All bytes in the string -** up to (but not including) the nul-terminator are written to the buffer. -** -** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before -** returning. -*/ -static void sessionAppendStr( - SessionBuffer *p, - const char *zStr, - int *pRc -){ - int nStr = sqlite3Strlen30(zStr); - if( 0==sessionBufferGrow(p, nStr+1, pRc) ){ - memcpy(&p->aBuf[p->nBuf], zStr, nStr); - p->nBuf += nStr; - p->aBuf[p->nBuf] = 0x00; - } -} - /* ** This function is a no-op if *pRc is other than SQLITE_OK when it is ** called. Otherwise, append the string representation of integer iVal @@ -221983,27 +223551,6 @@ static void sessionAppendInteger( sessionAppendStr(p, aBuf, pRc); } -static void sessionAppendPrintf( - SessionBuffer *p, /* Buffer to append to */ - int *pRc, - const char *zFmt, - ... -){ - if( *pRc==SQLITE_OK ){ - char *zApp = 0; - va_list ap; - va_start(ap, zFmt); - zApp = sqlite3_vmprintf(zFmt, ap); - if( zApp==0 ){ - *pRc = SQLITE_NOMEM; - }else{ - sessionAppendStr(p, zApp, pRc); - } - va_end(ap); - sqlite3_free(zApp); - } -} - /* ** This function is a no-op if *pRc is other than SQLITE_OK when it is ** called. Otherwise, append the string zStr enclosed in quotes (") and @@ -222494,26 +224041,16 @@ static int sessionGenerateChangeset( for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ if( pTab->nEntry ){ const char *zName = pTab->zName; - int nCol = 0; /* Number of columns in table */ - u8 *abPK = 0; /* Primary key array */ - const char **azCol = 0; /* Table columns */ int i; /* Used to iterate through hash buckets */ sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */ int nRewind = buf.nBuf; /* Initial size of write buffer */ int nNoop; /* Size of buffer after writing tbl header */ - int bRowid = 0; + int nOldCol = pTab->nCol; /* Check the table schema is still Ok. */ - rc = sessionTableInfo( - 0, db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK, - (pSession->bImplicitPK ? &bRowid : 0) - ); - if( rc==SQLITE_OK && ( - pTab->nCol!=nCol - || pTab->bRowid!=bRowid - || memcmp(abPK, pTab->abPK, nCol) - )){ - rc = SQLITE_SCHEMA; + rc = sessionReinitTable(pSession, pTab); + if( rc==SQLITE_OK && pTab->nCol!=nOldCol ){ + rc = sessionUpdateChanges(pSession, pTab); } /* Write a table header */ @@ -222521,8 +224058,8 @@ static int sessionGenerateChangeset( /* Build and compile a statement to execute: */ if( rc==SQLITE_OK ){ - rc = sessionSelectStmt( - db, 0, pSession->zDb, zName, bRowid, nCol, azCol, abPK, &pSel + rc = sessionSelectStmt(db, 0, pSession->zDb, + zName, pTab->bRowid, pTab->nCol, pTab->azCol, pTab->abPK, &pSel ); } @@ -222531,22 +224068,22 @@ static int sessionGenerateChangeset( SessionChange *p; /* Used to iterate through changes */ for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){ - rc = sessionSelectBind(pSel, nCol, abPK, p); + rc = sessionSelectBind(pSel, pTab->nCol, pTab->abPK, p); if( rc!=SQLITE_OK ) continue; if( sqlite3_step(pSel)==SQLITE_ROW ){ if( p->op==SQLITE_INSERT ){ int iCol; sessionAppendByte(&buf, SQLITE_INSERT, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); - for(iCol=0; iColnCol; iCol++){ sessionAppendCol(&buf, pSel, iCol, &rc); } }else{ - assert( abPK!=0 ); /* Because sessionSelectStmt() returned ok */ - rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK); + assert( pTab->abPK!=0 ); + rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, pTab->abPK); } }else if( p->op!=SQLITE_INSERT ){ - rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK); + rc = sessionAppendDelete(&buf, bPatchset, p, pTab->nCol,pTab->abPK); } if( rc==SQLITE_OK ){ rc = sqlite3_reset(pSel); @@ -222571,7 +224108,6 @@ static int sessionGenerateChangeset( if( buf.nBuf==nNoop ){ buf.nBuf = nRewind; } - sqlite3_free((char*)azCol); /* cast works around VC++ bug */ } } @@ -224700,7 +226236,7 @@ static int sessionChangesetApply( sqlite3changeset_pk(pIter, &abPK, 0); rc = sessionTableInfo(0, db, "main", zNew, - &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK, &sApply.bRowid + &sApply.nCol, &zTab, &sApply.azCol, 0, &sApply.abPK, &sApply.bRowid ); if( rc!=SQLITE_OK ) break; for(i=0; iflags & SQLITE_FkNoAction; + + if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){ + db->flags |= ((u64)SQLITE_FkNoAction); + db->aDb[0].pSchema->schema_cookie -= 32; + } + if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags ); } + + if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){ + assert( db->flags & SQLITE_FkNoAction ); + db->flags &= ~((u64)SQLITE_FkNoAction); + db->aDb[0].pSchema->schema_cookie -= 32; + } return rc; } @@ -224924,6 +226473,9 @@ struct sqlite3_changegroup { int rc; /* Error code */ int bPatch; /* True to accumulate patchsets */ SessionTable *pList; /* List of tables in current patch */ + + sqlite3 *db; /* Configured by changegroup_schema() */ + char *zDb; /* Configured by changegroup_schema() */ }; /* @@ -224944,6 +226496,7 @@ static int sessionChangeMerge( ){ SessionChange *pNew = 0; int rc = SQLITE_OK; + assert( aRec!=0 ); if( !pExist ){ pNew = (SessionChange *)sqlite3_malloc64(sizeof(SessionChange) + nRec); @@ -225109,6 +226662,114 @@ static int sessionChangeMerge( return rc; } +/* +** Check if a changeset entry with nCol columns and the PK array passed +** as the final argument to this function is compatible with SessionTable +** pTab. If so, return 1. Otherwise, if they are incompatible in some way, +** return 0. +*/ +static int sessionChangesetCheckCompat( + SessionTable *pTab, + int nCol, + u8 *abPK +){ + if( pTab->azCol && nColnCol ){ + int ii; + for(ii=0; iinCol; ii++){ + u8 bPK = (ii < nCol) ? abPK[ii] : 0; + if( pTab->abPK[ii]!=bPK ) return 0; + } + return 1; + } + return (pTab->nCol==nCol && 0==memcmp(abPK, pTab->abPK, nCol)); +} + +static int sessionChangesetExtendRecord( + sqlite3_changegroup *pGrp, + SessionTable *pTab, + int nCol, + int op, + const u8 *aRec, + int nRec, + SessionBuffer *pOut +){ + int rc = SQLITE_OK; + int ii = 0; + + assert( pTab->azCol ); + assert( nColnCol ); + + pOut->nBuf = 0; + if( op==SQLITE_INSERT || (op==SQLITE_DELETE && pGrp->bPatch==0) ){ + /* Append the missing default column values to the record. */ + sessionAppendBlob(pOut, aRec, nRec, &rc); + if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){ + rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt); + } + for(ii=nCol; rc==SQLITE_OK && iinCol; ii++){ + int eType = sqlite3_column_type(pTab->pDfltStmt, ii); + sessionAppendByte(pOut, eType, &rc); + switch( eType ){ + case SQLITE_FLOAT: + case SQLITE_INTEGER: { + i64 iVal; + if( eType==SQLITE_INTEGER ){ + iVal = sqlite3_column_int64(pTab->pDfltStmt, ii); + }else{ + double rVal = sqlite3_column_int64(pTab->pDfltStmt, ii); + memcpy(&iVal, &rVal, sizeof(i64)); + } + if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){ + sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal); + } + break; + } + + case SQLITE_BLOB: + case SQLITE_TEXT: { + int n = sqlite3_column_bytes(pTab->pDfltStmt, ii); + sessionAppendVarint(pOut, n, &rc); + if( eType==SQLITE_TEXT ){ + const u8 *z = (const u8*)sqlite3_column_text(pTab->pDfltStmt, ii); + sessionAppendBlob(pOut, z, n, &rc); + }else{ + const u8 *z = (const u8*)sqlite3_column_blob(pTab->pDfltStmt, ii); + sessionAppendBlob(pOut, z, n, &rc); + } + break; + } + + default: + assert( eType==SQLITE_NULL ); + break; + } + } + }else if( op==SQLITE_UPDATE ){ + /* Append missing "undefined" entries to the old.* record. And, if this + ** is an UPDATE, to the new.* record as well. */ + int iOff = 0; + if( pGrp->bPatch==0 ){ + for(ii=0; iinCol-nCol); ii++){ + sessionAppendByte(pOut, 0x00, &rc); + } + } + + sessionAppendBlob(pOut, &aRec[iOff], nRec-iOff, &rc); + for(ii=0; ii<(pTab->nCol-nCol); ii++){ + sessionAppendByte(pOut, 0x00, &rc); + } + }else{ + assert( op==SQLITE_DELETE && pGrp->bPatch ); + sessionAppendBlob(pOut, aRec, nRec, &rc); + } + + return rc; +} + /* ** Add all changes in the changeset traversed by the iterator passed as ** the first argument to the changegroup hash tables. @@ -225122,6 +226783,7 @@ static int sessionChangesetToHash( int nRec; int rc = SQLITE_OK; SessionTable *pTab = 0; + SessionBuffer rec = {0, 0, 0}; while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, 0) ){ const char *zNew; @@ -225133,6 +226795,9 @@ static int sessionChangesetToHash( SessionChange *pExist = 0; SessionChange **pp; + /* Ensure that only changesets, or only patchsets, but not a mixture + ** of both, are being combined. It is an error to try to combine a + ** changeset and a patchset. */ if( pGrp->pList==0 ){ pGrp->bPatch = pIter->bPatchset; }else if( pIter->bPatchset!=pGrp->bPatch ){ @@ -225165,18 +226830,38 @@ static int sessionChangesetToHash( pTab->zName = (char*)&pTab->abPK[nCol]; memcpy(pTab->zName, zNew, nNew+1); + if( pGrp->db ){ + pTab->nCol = 0; + rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb); + if( rc ){ + assert( pTab->azCol==0 ); + sqlite3_free(pTab); + break; + } + } + /* The new object must be linked on to the end of the list, not ** simply added to the start of it. This is to ensure that the ** tables within the output of sqlite3changegroup_output() are in ** the right order. */ for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext); *ppTab = pTab; - }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){ + } + + if( !sessionChangesetCheckCompat(pTab, nCol, abPK) ){ rc = SQLITE_SCHEMA; break; } } + if( nColnCol ){ + assert( pGrp->db ); + rc = sessionChangesetExtendRecord(pGrp, pTab, nCol, op, aRec, nRec, &rec); + if( rc ) break; + aRec = rec.aBuf; + nRec = rec.nBuf; + } + if( sessionGrowHash(0, pIter->bPatchset, pTab) ){ rc = SQLITE_NOMEM; break; @@ -225214,6 +226899,7 @@ static int sessionChangesetToHash( } } + sqlite3_free(rec.aBuf); if( rc==SQLITE_OK ) rc = pIter->rc; return rc; } @@ -225300,6 +226986,31 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){ return rc; } +/* +** Provide a database schema to the changegroup object. +*/ +SQLITE_API int sqlite3changegroup_schema( + sqlite3_changegroup *pGrp, + sqlite3 *db, + const char *zDb +){ + int rc = SQLITE_OK; + + if( pGrp->pList || pGrp->db ){ + /* Cannot add a schema after one or more calls to sqlite3changegroup_add(), + ** or after sqlite3changegroup_schema() has already been called. */ + rc = SQLITE_MISUSE; + }else{ + pGrp->zDb = sqlite3_mprintf("%s", zDb); + if( pGrp->zDb==0 ){ + rc = SQLITE_NOMEM; + }else{ + pGrp->db = db; + } + } + return rc; +} + /* ** Add the changeset currently stored in buffer pData, size nData bytes, ** to changeset-group p. @@ -225363,6 +227074,7 @@ SQLITE_API int sqlite3changegroup_output_strm( */ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ if( pGrp ){ + sqlite3_free(pGrp->zDb); sessionDeleteTable(0, pGrp->pList); sqlite3_free(pGrp); } @@ -228868,15 +230580,19 @@ static int fts5CInstIterInit( */ typedef struct HighlightContext HighlightContext; struct HighlightContext { - CInstIter iter; /* Coalesced Instance Iterator */ - int iPos; /* Current token offset in zIn[] */ + /* Constant parameters to fts5HighlightCb() */ int iRangeStart; /* First token to include */ int iRangeEnd; /* If non-zero, last token to include */ const char *zOpen; /* Opening highlight */ const char *zClose; /* Closing highlight */ const char *zIn; /* Input text */ int nIn; /* Size of input text in bytes */ - int iOff; /* Current offset within zIn[] */ + + /* Variables modified by fts5HighlightCb() */ + CInstIter iter; /* Coalesced Instance Iterator */ + int iPos; /* Current token offset in zIn[] */ + int iOff; /* Have copied up to this offset in zIn[] */ + int bOpen; /* True if highlight is open */ char *zOut; /* Output value */ }; @@ -228909,8 +230625,8 @@ static int fts5HighlightCb( int tflags, /* Mask of FTS5_TOKEN_* flags */ const char *pToken, /* Buffer containing token */ int nToken, /* Size of token in bytes */ - int iStartOff, /* Start offset of token */ - int iEndOff /* End offset of token */ + int iStartOff, /* Start byte offset of token */ + int iEndOff /* End byte offset of token */ ){ HighlightContext *p = (HighlightContext*)pContext; int rc = SQLITE_OK; @@ -228926,30 +230642,47 @@ static int fts5HighlightCb( if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff; } - if( iPos==p->iter.iStart ){ + /* If the parenthesis is open, and this token is not part of the current + ** phrase, and the starting byte offset of this token is past the point + ** that has currently been copied into the output buffer, close the + ** parenthesis. */ + if( p->bOpen + && (iPos<=p->iter.iStart || p->iter.iStart<0) + && iStartOff>p->iOff + ){ + fts5HighlightAppend(&rc, p, p->zClose, -1); + p->bOpen = 0; + } + + /* If this is the start of a new phrase, and the highlight is not open: + ** + ** * copy text from the input up to the start of the phrase, and + ** * open the highlight. + */ + if( iPos==p->iter.iStart && p->bOpen==0 ){ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff); fts5HighlightAppend(&rc, p, p->zOpen, -1); p->iOff = iStartOff; + p->bOpen = 1; } if( iPos==p->iter.iEnd ){ - if( p->iRangeEnd>=0 && p->iter.iStartiRangeStart ){ + if( p->bOpen==0 ){ + assert( p->iRangeEnd>=0 ); fts5HighlightAppend(&rc, p, p->zOpen, -1); + p->bOpen = 1; } fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); - fts5HighlightAppend(&rc, p, p->zClose, -1); p->iOff = iEndOff; + if( rc==SQLITE_OK ){ rc = fts5CInstIterNext(&p->iter); } } - if( p->iRangeEnd>=0 && iPos==p->iRangeEnd ){ + if( iPos==p->iRangeEnd ){ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); p->iOff = iEndOff; - if( iPos>=p->iter.iStart && iPositer.iEnd ){ - fts5HighlightAppend(&rc, p, p->zClose, -1); - } } return rc; @@ -228990,6 +230723,9 @@ static void fts5HighlightFunction( if( rc==SQLITE_OK ){ rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); } + if( ctx.bOpen ){ + fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1); + } fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); if( rc==SQLITE_OK ){ @@ -229268,6 +231004,9 @@ static void fts5SnippetFunction( if( rc==SQLITE_OK ){ rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); } + if( ctx.bOpen ){ + fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1); + } if( ctx.iRangeEnd>=(nColSize-1) ){ fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); }else{ @@ -234485,10 +236224,8 @@ static Fts5HashEntry *fts5HashEntryMerge( } /* -** Extract all tokens from hash table iHash and link them into a list -** in sorted order. The hash table is cleared before returning. It is -** the responsibility of the caller to free the elements of the returned -** list. +** Link all tokens from hash table iHash into a list in sorted order. The +** tokens are not removed from the hash table. */ static int fts5HashEntrySort( Fts5Hash *pHash, @@ -237354,6 +239091,14 @@ static void fts5SegIterHashInit( pLeaf->p = (u8*)pList; } } + + /* The call to sqlite3Fts5HashScanInit() causes the hash table to + ** fill the size field of all existing position lists. This means they + ** can no longer be appended to. Since the only scenario in which they + ** can be appended to is if the previous operation on this table was + ** a DELETE, by clearing the Fts5Index.bDelete flag we can avoid this + ** possibility altogether. */ + p->bDelete = 0; }else{ p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data), (const char*)pTerm, nTerm, (void**)&pLeaf, &nList @@ -237539,7 +239284,6 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){ assert_nc( i2!=0 ); pRes->bTermEq = 1; if( p1->iRowid==p2->iRowid ){ - p1->bDel = p2->bDel; return i2; } res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1; @@ -237907,7 +239651,7 @@ static Fts5Iter *fts5MultiIterAlloc( int nSeg ){ Fts5Iter *pNew; - int nSlot; /* Power of two >= nSeg */ + i64 nSlot; /* Power of two >= nSeg */ for(nSlot=2; nSlotpConfig->pgsz>0 ); + assert( p->pConfig->pgsz>0 || p->rc!=SQLITE_OK ); while( p->rc==SQLITE_OK && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz ){ @@ -239683,7 +241427,6 @@ static void fts5DoSecureDelete( int iPgIdx = pSeg->pLeaf->szLeaf; u64 iDelta = 0; - u64 iNextDelta = 0; int iNextOff = 0; int iOff = 0; int nIdx = 0; @@ -239691,7 +241434,6 @@ static void fts5DoSecureDelete( int bLastInDoclist = 0; int iIdx = 0; int iStart = 0; - int iKeyOff = 0; int iDelKeyOff = 0; /* Offset of deleted key, if any */ nIdx = nPg-iPgIdx; @@ -239716,10 +241458,21 @@ static void fts5DoSecureDelete( ** This block sets the following variables: ** ** iStart: + ** The offset of the first byte of the rowid or delta-rowid + ** value for the doclist entry being removed. + ** ** iDelta: + ** The value of the rowid or delta-rowid value for the doclist + ** entry being removed. + ** + ** iNextOff: + ** The offset of the next entry following the position list + ** for the one being removed. If the position list for this + ** entry overflows onto the next leaf page, this value will be + ** greater than pLeaf->szLeaf. */ { - int iSOP; + int iSOP; /* Start-Of-Position-list */ if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){ iStart = pSeg->iTermLeafOffset; }else{ @@ -239755,47 +241508,81 @@ static void fts5DoSecureDelete( } iOff = iStart; + + /* If the position-list for the entry being removed flows over past + ** the end of this page, delete the portion of the position-list on the + ** next page and beyond. + ** + ** Set variable bLastInDoclist to true if this entry happens + ** to be the last rowid in the doclist for its term. */ if( iNextOff>=iPgIdx ){ int pgno = pSeg->iLeafPgno+1; fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist); iNextOff = iPgIdx; - }else{ - /* Set bLastInDoclist to true if the entry being removed is the last - ** in its doclist. */ - for(iIdx=0, iKeyOff=0; iIdxbDel==0 ){ + if( iNextOff!=iPgIdx ){ + /* Loop through the page-footer. If iNextOff (offset of the + ** entry following the one we are removing) is equal to the + ** offset of a key on this page, then the entry is the last + ** in its doclist. */ + int iKeyOff = 0; + for(iIdx=0; iIdxbDel ){ + iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta); + aPg[iOff++] = 0x01; + }else if( bLastInDoclist==0 ){ if( iNextOff!=iPgIdx ){ + u64 iNextDelta = 0; iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta); iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta + iNextDelta); } }else if( - iStart==pSeg->iTermLeafOffset && pSeg->iLeafPgno==pSeg->iTermLeafPgno + pSeg->iLeafPgno==pSeg->iTermLeafPgno + && iStart==pSeg->iTermLeafOffset ){ /* The entry being removed was the only position list in its ** doclist. Therefore the term needs to be removed as well. */ int iKey = 0; - for(iIdx=0, iKeyOff=0; iIdx(u32)iStart ) break; iKeyOff += iVal; } + assert_nc( iKey>=1 ); + /* Set iDelKeyOff to the value of the footer entry to remove from + ** the page. */ iDelKeyOff = iOff = iKeyOff; + if( iNextOff!=iPgIdx ){ + /* This is the only position-list associated with the term, and there + ** is another term following it on this page. So the subsequent term + ** needs to be moved to replace the term associated with the entry + ** being removed. */ int nPrefix = 0; int nSuffix = 0; int nPrefix2 = 0; @@ -239874,6 +241661,15 @@ static void fts5DoSecureDelete( } } + /* Assuming no error has occurred, this block does final edits to the + ** leaf page before writing it back to disk. Input variables are: + ** + ** nPg: Total initial size of leaf page. + ** iPgIdx: Initial offset of page footer. + ** + ** iOff: Offset to move data to + ** iNextOff: Offset to move data from + */ if( p->rc==SQLITE_OK ){ const int nMove = nPg - iNextOff; /* Number of bytes to move */ int nShift = iNextOff - iOff; /* Distance to move them */ @@ -240074,10 +241870,16 @@ static void fts5FlushOneHash(Fts5Index *p){ fts5WriteFlushLeaf(p, &writer); } }else{ - int bDummy; - int nPos; - int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy); - nCopy += nPos; + int bDel = 0; + int nPos = 0; + int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDel); + if( bDel && bSecureDelete ){ + fts5BufferAppendVarint(&p->rc, pBuf, nPos*2); + iOff += nCopy; + nCopy = nPos; + }else{ + nCopy += nPos; + } if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){ /* The entire poslist will fit on the current leaf. So copy ** it in one go. */ @@ -240115,7 +241917,6 @@ static void fts5FlushOneHash(Fts5Index *p){ assert( pBuf->n<=pBuf->nSpace ); if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash); } - sqlite3Fts5HashClear(pHash); fts5WriteFinish(p, &writer, &pgnoLast); assert( p->rc!=SQLITE_OK || bSecureDelete || pgnoLast>0 ); @@ -240148,7 +241949,6 @@ static void fts5FlushOneHash(Fts5Index *p){ fts5IndexCrisismerge(p, &pStruct); fts5StructureWrite(p, pStruct); fts5StructureRelease(pStruct); - p->nContentlessDelete = 0; } /* @@ -240159,8 +241959,12 @@ static void fts5IndexFlush(Fts5Index *p){ if( p->nPendingData || p->nContentlessDelete ){ assert( p->pHash ); fts5FlushOneHash(p); - p->nPendingData = 0; - p->nPendingRow = 0; + if( p->rc==SQLITE_OK ){ + sqlite3Fts5HashClear(p->pHash); + p->nPendingData = 0; + p->nPendingRow = 0; + p->nContentlessDelete = 0; + } } } @@ -240238,8 +242042,9 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){ assert( p->rc==SQLITE_OK ); fts5IndexFlush(p); - assert( p->nContentlessDelete==0 ); + assert( p->rc!=SQLITE_OK || p->nContentlessDelete==0 ); pStruct = fts5StructureRead(p); + assert( p->rc!=SQLITE_OK || pStruct!=0 ); fts5StructureInvalidate(p); if( pStruct ){ @@ -242902,7 +244707,8 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0 /* xShadowName */ + 0, /* xShadowName */ + 0 /* xIntegrity */ }; rc = sqlite3_create_module(db, "fts5_structure", &fts5structure_module, 0); } @@ -243041,6 +244847,8 @@ struct Fts5FullTable { Fts5Storage *pStorage; /* Document store */ Fts5Global *pGlobal; /* Global (connection wide) data */ Fts5Cursor *pSortCsr; /* Sort data from this cursor */ + int iSavepoint; /* Successful xSavepoint()+1 */ + int bInSavepoint; #ifdef SQLITE_DEBUG struct Fts5TransactionState ts; #endif @@ -243329,6 +245137,13 @@ static int fts5InitVtab( pConfig->pzErrmsg = 0; } + if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ + rc = sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, (int)1); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); + } + if( rc!=SQLITE_OK ){ fts5FreeVtab(pTab); pTab = 0; @@ -244278,9 +246093,8 @@ static int fts5FilterMethod( pCsr->pExpr = pTab->pSortCsr->pExpr; rc = fts5CursorFirst(pTab, pCsr, bDesc); }else if( pCsr->pExpr ){ - if( rc==SQLITE_OK ){ - rc = fts5CursorParseRank(pConfig, pCsr, pRank); - } + assert( rc==SQLITE_OK ); + rc = fts5CursorParseRank(pConfig, pCsr, pRank); if( rc==SQLITE_OK ){ if( bOrderByRank ){ pCsr->ePlan = FTS5_PLAN_SORTED_MATCH; @@ -244451,6 +246265,7 @@ static int fts5SpecialInsert( Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; int bError = 0; + int bLoadConfig = 0; if( 0==sqlite3_stricmp("delete-all", zCmd) ){ if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ @@ -244462,6 +246277,7 @@ static int fts5SpecialInsert( }else{ rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage); } + bLoadConfig = 1; }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){ if( pConfig->eContent==FTS5_CONTENT_NONE ){ fts5SetVtabError(pTab, @@ -244471,6 +246287,7 @@ static int fts5SpecialInsert( }else{ rc = sqlite3Fts5StorageRebuild(pTab->pStorage); } + bLoadConfig = 1; }else if( 0==sqlite3_stricmp("optimize", zCmd) ){ rc = sqlite3Fts5StorageOptimize(pTab->pStorage); }else if( 0==sqlite3_stricmp("merge", zCmd) ){ @@ -244483,6 +246300,8 @@ static int fts5SpecialInsert( }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){ pConfig->bPrefixIndex = sqlite3_value_int(pVal); #endif + }else if( 0==sqlite3_stricmp("flush", zCmd) ){ + rc = sqlite3Fts5FlushToDisk(&pTab->p); }else{ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); if( rc==SQLITE_OK ){ @@ -244496,6 +246315,12 @@ static int fts5SpecialInsert( } } } + + if( rc==SQLITE_OK && bLoadConfig ){ + pTab->p.pConfig->iCookie--; + rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); + } + return rc; } @@ -244614,7 +246439,7 @@ static int fts5UpdateMethod( assert( nArg!=1 || eType0==SQLITE_INTEGER ); /* Filter out attempts to run UPDATE or DELETE on contentless tables. - ** This is not suported. Except - DELETE is supported if the CREATE + ** This is not suported. Except - they are both supported if the CREATE ** VIRTUAL TABLE statement contained "contentless_delete=1". */ if( eType0==SQLITE_INTEGER && pConfig->eContent==FTS5_CONTENT_NONE @@ -244643,7 +246468,8 @@ static int fts5UpdateMethod( } else if( eType0!=SQLITE_INTEGER ){ - /* If this is a REPLACE, first remove the current entry (if any) */ + /* An INSERT statement. If the conflict-mode is REPLACE, first remove + ** the current entry (if any). */ if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){ i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); @@ -245517,8 +247343,12 @@ static int fts5RenameMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ const char *zName /* New name of table */ ){ + int rc; Fts5FullTable *pTab = (Fts5FullTable*)pVtab; - return sqlite3Fts5StorageRename(pTab->pStorage, zName); + pTab->bInSavepoint = 1; + rc = sqlite3Fts5StorageRename(pTab->pStorage, zName); + pTab->bInSavepoint = 0; + return rc; } static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){ @@ -245532,9 +247362,29 @@ static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){ ** Flush the contents of the pending-terms table to disk. */ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ - UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ - fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint); - return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; + int rc = SQLITE_OK; + char *zSql = 0; + fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); + + if( pTab->bInSavepoint==0 ){ + zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')", + pTab->p.pConfig->zDb, pTab->p.pConfig->zName, pTab->p.pConfig->zName + ); + if( zSql ){ + pTab->bInSavepoint = 1; + rc = sqlite3_exec(pTab->p.pConfig->db, zSql, 0, 0, 0); + pTab->bInSavepoint = 0; + sqlite3_free(zSql); + }else{ + rc = SQLITE_NOMEM; + } + if( rc==SQLITE_OK ){ + pTab->iSavepoint = iSavepoint+1; + } + } + + return rc; } /* @@ -245543,9 +247393,16 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ ** This is a no-op. */ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ - UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ - fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint); - return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; + int rc = SQLITE_OK; + fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint); + if( (iSavepoint+1)iSavepoint ){ + rc = sqlite3Fts5FlushToDisk(&pTab->p); + if( rc==SQLITE_OK ){ + pTab->iSavepoint = iSavepoint; + } + } + return rc; } /* @@ -245555,11 +247412,14 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ */ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; - UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ + int rc = SQLITE_OK; fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); fts5TripCursors(pTab); pTab->p.pConfig->pgsz = 0; - return sqlite3Fts5StorageRollback(pTab->pStorage); + if( (iSavepoint+1)<=pTab->iSavepoint ){ + rc = sqlite3Fts5StorageRollback(pTab->pStorage); + } + return rc; } /* @@ -245761,7 +247621,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2023-10-10 12:14:04 4310099cce5a487035fa535dd3002c59ac7f1d1bec68d7cf317fd3e769484790", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2023-11-24 11:41:44 ebead0e7230cd33bcec9f95d2183069565b9e709bf745c9b5db65cc0cbf92c0f", -1, SQLITE_TRANSIENT); } /* @@ -245779,9 +247639,46 @@ static int fts5ShadowName(const char *zName){ return 0; } +/* +** Run an integrity check on the FTS5 data structures. Return a string +** if anything is found amiss. Return a NULL pointer if everything is +** OK. +*/ +static int fts5Integrity( + sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */ + const char *zSchema, /* Name of schema in which this table lives */ + const char *zTabname, /* Name of the table itself */ + int isQuick, /* True if this is a quick-check */ + char **pzErr /* Write error message here */ +){ + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; + Fts5Config *pConfig = pTab->p.pConfig; + char *zSql; + char *zErr = 0; + int rc; + assert( pzErr!=0 && *pzErr==0 ); + UNUSED_PARAM(isQuick); + zSql = sqlite3_mprintf( + "INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');", + zSchema, zTabname, pConfig->zName); + if( zSql==0 ) return SQLITE_NOMEM; + rc = sqlite3_exec(pConfig->db, zSql, 0, 0, &zErr); + sqlite3_free(zSql); + if( (rc&0xff)==SQLITE_CORRUPT ){ + *pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s", + zSchema, zTabname); + }else if( rc!=SQLITE_OK ){ + *pzErr = sqlite3_mprintf("unable to validate the inverted index for" + " FTS5 table %s.%s: %s", + zSchema, zTabname, zErr); + } + sqlite3_free(zErr); + return SQLITE_OK; +} + static int fts5Init(sqlite3 *db){ static const sqlite3_module fts5Mod = { - /* iVersion */ 3, + /* iVersion */ 4, /* xCreate */ fts5CreateMethod, /* xConnect */ fts5ConnectMethod, /* xBestIndex */ fts5BestIndexMethod, @@ -245804,7 +247701,8 @@ static int fts5Init(sqlite3 *db){ /* xSavepoint */ fts5SavepointMethod, /* xRelease */ fts5ReleaseMethod, /* xRollbackTo */ fts5RollbackToMethod, - /* xShadowName */ fts5ShadowName + /* xShadowName */ fts5ShadowName, + /* xIntegrity */ fts5Integrity }; int rc; @@ -247081,7 +248979,9 @@ static int sqlite3Fts5StorageSync(Fts5Storage *p){ i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db); if( p->bTotalsValid ){ rc = fts5StorageSaveTotals(p); - p->bTotalsValid = 0; + if( rc==SQLITE_OK ){ + p->bTotalsValid = 0; + } } if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexSync(p->pIndex); @@ -250449,7 +252349,8 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, - /* xShadowName */ 0 + /* xShadowName */ 0, + /* xIntegrity */ 0 }; void *p = (void*)pGlobal; @@ -250778,6 +252679,7 @@ static sqlite3_module stmtModule = { 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ + 0 /* xIntegrity */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/src/3rdparty/sqlite3/src/sqlite3.h b/src/3rdparty/sqlite3/src/sqlite3.h index 03761134..ef0237bd 100644 --- a/src/3rdparty/sqlite3/src/sqlite3.h +++ b/src/3rdparty/sqlite3/src/sqlite3.h @@ -146,9 +146,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.43.2" -#define SQLITE_VERSION_NUMBER 3043002 -#define SQLITE_SOURCE_ID "2023-10-10 12:14:04 4310099cce5a487035fa535dd3002c59ac7f1d1bec68d7cf317fd3e769484790" +#define SQLITE_VERSION "3.44.2" +#define SQLITE_VERSION_NUMBER 3044002 +#define SQLITE_SOURCE_ID "2023-11-24 11:41:44 ebead0e7230cd33bcec9f95d2183069565b9e709bf745c9b5db65cc0cbf92c0f" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -2127,7 +2127,7 @@ struct sqlite3_mem_methods { ** is stored in each sorted record and the required column values loaded ** from the database as records are returned in sorted order. The default ** value for this option is to never use this optimization. Specifying a -** negative value for this option restores the default behaviour. +** negative value for this option restores the default behavior. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. ** @@ -2302,7 +2302,7 @@ struct sqlite3_mem_methods { ** database handle, SQLite checks if this will mean that there are now no ** connections at all to the database. If so, it performs a checkpoint ** operation before closing the connection. This option may be used to -** override this behaviour. The first parameter passed to this operation +** override this behavior. The first parameter passed to this operation ** is an integer - positive to disable checkpoints-on-close, or zero (the ** default) to enable them, and negative to leave the setting unchanged. ** The second parameter is a pointer to an integer @@ -3955,6 +3955,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively. +** (See how SQLite handles [invalid UTF] for exceptions to this rule.) ** ^(Memory to hold the error message string is managed internally. ** The application does not need to worry about freeing the result. ** However, the error string might be overwritten or deallocated by @@ -5325,6 +5326,7 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); */ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); + /* ** CAPI3REF: Create Or Redefine SQL Functions ** KEYWORDS: {function creation routines} @@ -5571,13 +5573,27 @@ SQLITE_API int sqlite3_create_window_function( **
    ** ** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    -** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call +** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. -** Specifying this flag makes no difference for scalar or aggregate user -** functions. However, if it is not specified for a user-defined window -** function, then any sub-types belonging to arguments passed to the window -** function may be discarded before the window function is called (i.e. -** sqlite3_value_subtype() will always return 0). +** This flag instructs SQLite to omit some corner-case optimizations that +** might disrupt the operation of the [sqlite3_value_subtype()] function, +** causing it to return zero rather than the correct subtype(). +** SQL functions that invokes [sqlite3_value_subtype()] should have this +** property. If the SQLITE_SUBTYPE property is omitted, then the return +** value from [sqlite3_value_subtype()] might sometimes be zero even though +** a non-zero subtype was specified by the function argument expression. +** +** [[SQLITE_RESULT_SUBTYPE]]
    SQLITE_RESULT_SUBTYPE
    +** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call +** [sqlite3_result_subtype()] to cause a sub-type to be associated with its +** result. +** Every function that invokes [sqlite3_result_subtype()] should have this +** property. If it does not, then the call to [sqlite3_result_subtype()] +** might become a no-op if the function is used as term in an +** [expression index]. On the other hand, SQL functions that never invoke +** [sqlite3_result_subtype()] should avoid setting this property, as the +** purpose of this property is to disable certain optimizations that are +** incompatible with subtypes. **
    ** */ @@ -5585,6 +5601,7 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_DIRECTONLY 0x000080000 #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 +#define SQLITE_RESULT_SUBTYPE 0x001000000 /* ** CAPI3REF: Deprecated Functions @@ -5781,6 +5798,12 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. +** +** Every [application-defined SQL function] that invoke this interface +** should include the [SQLITE_SUBTYPE] property in the text +** encoding argument when the function is [sqlite3_create_function|registered]. +** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() +** might return zero instead of the upstream subtype in some corner cases. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); @@ -5879,48 +5902,56 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** METHOD: sqlite3_context ** ** These functions may be used by (non-aggregate) SQL functions to -** associate metadata with argument values. If the same value is passed to -** multiple invocations of the same SQL function during query execution, under -** some circumstances the associated metadata may be preserved. An example -** of where this might be useful is in a regular-expression matching -** function. The compiled version of the regular expression can be stored as -** metadata associated with the pattern string. +** associate auxiliary data with argument values. If the same argument +** value is passed to multiple invocations of the same SQL function during +** query execution, under some circumstances the associated auxiliary data +** might be preserved. An example of where this might be useful is in a +** regular-expression matching function. The compiled version of the regular +** expression can be stored as auxiliary data associated with the pattern string. ** Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data ** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument ** value to the application-defined function. ^N is zero for the left-most -** function argument. ^If there is no metadata +** function argument. ^If there is no auxiliary data ** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** -** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th -** argument of the application-defined function. ^Subsequent +** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the +** N-th argument of the application-defined function. ^Subsequent ** calls to sqlite3_get_auxdata(C,N) return P from the most recent -** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or -** NULL if the metadata has been discarded. +** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or +** NULL if the auxiliary data has been discarded. ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, ** SQLite will invoke the destructor function X with parameter P exactly -** once, when the metadata is discarded. -** SQLite is free to discard the metadata at any time, including:
      +** once, when the auxiliary data is discarded. +** SQLite is free to discard the auxiliary data at any time, including:
        **
      • ^(when the corresponding function parameter changes)^, or **
      • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** SQL statement)^, or **
      • ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or **
      • ^(during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.)^
      +** allocation error occurs.)^ +**
    • ^(during the original sqlite3_set_auxdata() call if the function +** is evaluated during query planning instead of during query execution, +** as sometimes happens with [SQLITE_ENABLE_STAT4].)^
    ** -** Note the last bullet in particular. The destructor X in +** Note the last two bullets in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the ** function implementation should not make any use of P after -** sqlite3_set_auxdata() has been called. -** -** ^(In practice, metadata is preserved between function calls for +** sqlite3_set_auxdata() has been called. Furthermore, a call to +** sqlite3_get_auxdata() that occurs immediately after a corresponding call +** to sqlite3_set_auxdata() might still return NULL if an out-of-memory +** condition occurred during the sqlite3_set_auxdata() call or if the +** function is being evaluated during query planning rather than during +** query execution. +** +** ^(In practice, auxiliary data is preserved between function calls for ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** @@ -5930,10 +5961,67 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** ** These routines must be called from the same thread in which ** the SQL function is running. +** +** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()]. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); +/* +** CAPI3REF: Database Connection Client Data +** METHOD: sqlite3 +** +** These functions are used to associate one or more named pointers +** with a [database connection]. +** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P +** to be attached to [database connection] D using name N. Subsequent +** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P +** or a NULL pointer if there were no prior calls to +** sqlite3_set_clientdata() with the same values of D and N. +** Names are compared using strcmp() and are thus case sensitive. +** +** If P and X are both non-NULL, then the destructor X is invoked with +** argument P on the first of the following occurrences: +**
      +**
    • An out-of-memory error occurs during the call to +** sqlite3_set_clientdata() which attempts to register pointer P. +**
    • A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made +** with the same D and N parameters. +**
    • The database connection closes. SQLite does not make any guarantees +** about the order in which destructors are called, only that all +** destructors will be called exactly once at some point during the +** database connection closing process. +**
    +** +** SQLite does not do anything with client data other than invoke +** destructors on the client data at the appropriate time. The intended +** use for client data is to provide a mechanism for wrapper libraries +** to store additional information about an SQLite database connection. +** +** There is no limit (other than available memory) on the number of different +** client data pointers (with different names) that can be attached to a +** single database connection. However, the implementation is optimized +** for the case of having only one or two different client data names. +** Applications and wrapper libraries are discouraged from using more than +** one client data name each. +** +** There is no way to enumerate the client data pointers +** associated with a database connection. The N parameter can be thought +** of as a secret key such that only code that knows the secret key is able +** to access the associated data. +** +** Security Warning: These interfaces should not be exposed in scripting +** languages or in other circumstances where it might be possible for an +** an attacker to invoke them. Any agent that can invoke these interfaces +** can probably also take control of the process. +** +** Database connection client data is only available for SQLite +** version 3.44.0 ([dateof:3.44.0]) and later. +** +** See also: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()]. +*/ +SQLITE_API void *sqlite3_get_clientdata(sqlite3*,const char*); +SQLITE_API int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*)); /* ** CAPI3REF: Constants Defining Special Destructor Behavior @@ -6135,6 +6223,20 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); ** higher order bits are discarded. ** The number of subtype bytes preserved by SQLite might increase ** in future releases of SQLite. +** +** Every [application-defined SQL function] that invokes this interface +** should include the [SQLITE_RESULT_SUBTYPE] property in its +** text encoding argument when the SQL function is +** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE] +** property is omitted from the function that invokes sqlite3_result_subtype(), +** then in some cases the sqlite3_result_subtype() might fail to set +** the result subtype. +** +** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any +** SQL function that invokes the sqlite3_result_subtype() interface +** and that does not have the SQLITE_RESULT_SUBTYPE property will raise +** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1 +** by default. */ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); @@ -6566,7 +6668,7 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); /* -** CAPI3REF: Allowed return values from [sqlite3_txn_state()] +** CAPI3REF: Allowed return values from sqlite3_txn_state() ** KEYWORDS: {transaction state} ** ** These constants define the current transaction state of a database file. @@ -6698,7 +6800,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); ** ^Each call to the sqlite3_autovacuum_pages() interface overrides all ** previous invocations for that database connection. ^If the callback ** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, -** then the autovacuum steps callback is cancelled. The return value +** then the autovacuum steps callback is canceled. The return value ** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might ** be some other error code if something goes wrong. The current ** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other @@ -7217,6 +7319,10 @@ struct sqlite3_module { /* The methods above are in versions 1 and 2 of the sqlite_module object. ** Those below are for version 3 and greater. */ int (*xShadowName)(const char*); + /* The methods above are in versions 1 through 3 of the sqlite_module object. + ** Those below are for version 4 and greater. */ + int (*xIntegrity)(sqlite3_vtab *pVTab, const char *zSchema, + const char *zTabName, int mFlags, char **pzErr); }; /* @@ -7704,7 +7810,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); ** code is returned and the transaction rolled back. ** ** Calling this function with an argument that is not a NULL pointer or an -** open blob handle results in undefined behaviour. ^Calling this routine +** open blob handle results in undefined behavior. ^Calling this routine ** with a null pointer (such as would be returned by a failed call to ** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function ** is passed a valid open blob handle, the values returned by the @@ -8184,6 +8290,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_PRNG_SAVE 5 #define SQLITE_TESTCTRL_PRNG_RESTORE 6 #define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */ +#define SQLITE_TESTCTRL_FK_NO_ACTION 7 #define SQLITE_TESTCTRL_BITVEC_TEST 8 #define SQLITE_TESTCTRL_FAULT_INSTALL 9 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 @@ -9245,8 +9352,8 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** blocked connection already has a registered unlock-notify callback, ** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is ** called with a NULL pointer as its second argument, then any existing -** unlock-notify callback is cancelled. ^The blocked connections -** unlock-notify callback may also be cancelled by closing the blocked +** unlock-notify callback is canceled. ^The blocked connections +** unlock-notify callback may also be canceled by closing the blocked ** connection using [sqlite3_close()]. ** ** The unlock-notify callback is not reentrant. If an application invokes @@ -10549,6 +10656,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c ** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** +** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set, +** the returned buffer content will remain accessible and unchanged +** until either the next write operation on the connection or when +** the connection is closed, and applications must not modify the +** buffer. If the bit had been clear, the returned buffer will not +** be accessed by SQLite after the call. +** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** allocation error occurs. @@ -10597,6 +10711,9 @@ SQLITE_API unsigned char *sqlite3_serialize( ** SQLite will try to increase the buffer size using sqlite3_realloc64() ** if writes on the database cause it to grow larger than M bytes. ** +** Applications must not modify the buffer P or invalidate it before +** the database connection D is closed. +** ** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. @@ -10605,6 +10722,13 @@ SQLITE_API unsigned char *sqlite3_serialize( ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the ** function returns SQLITE_ERROR. ** +** The deserialized database should not be in [WAL mode]. If the database +** is in WAL mode, then any attempt to use the database file will result +** in an [SQLITE_CANTOPEN] error. The application can set the +** [file format version numbers] (bytes 18 and 19) of the input database P +** to 0x01 prior to invoking sqlite3_deserialize(D,S,P,N,M,F) to force the +** database file into rollback mode and work around this limitation. +** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. @@ -11677,6 +11801,18 @@ SQLITE_API int sqlite3changeset_concat( ); +/* +** CAPI3REF: Upgrade the Schema of a Changeset/Patchset +*/ +SQLITE_API int sqlite3changeset_upgrade( + sqlite3 *db, + const char *zDb, + int nIn, const void *pIn, /* Input changeset */ + int *pnOut, void **ppOut /* OUT: Inverse of input */ +); + + + /* ** CAPI3REF: Changegroup Handle ** @@ -11723,6 +11859,38 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; */ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); +/* +** CAPI3REF: Add a Schema to a Changegroup +** METHOD: sqlite3_changegroup_schema +** +** This method may be used to optionally enforce the rule that the changesets +** added to the changegroup handle must match the schema of database zDb +** ("main", "temp", or the name of an attached database). If +** sqlite3changegroup_add() is called to add a changeset that is not compatible +** with the configured schema, SQLITE_SCHEMA is returned and the changegroup +** object is left in an undefined state. +** +** A changeset schema is considered compatible with the database schema in +** the same way as for sqlite3changeset_apply(). Specifically, for each +** table in the changeset, there exists a database table with: +** +**
      +**
    • The name identified by the changeset, and +**
    • at least as many columns as recorded in the changeset, and +**
    • the primary key columns in the same position as recorded in +** the changeset. +**
    +** +** The output of the changegroup object always has the same schema as the +** database nominated using this function. In cases where changesets passed +** to sqlite3changegroup_add() have fewer columns than the corresponding table +** in the database schema, these are filled in using the default column +** values from the database schema. This makes it possible to combined +** changesets that have different numbers of columns for a single table +** within a changegroup, provided that they are otherwise compatible. +*/ +SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb); + /* ** CAPI3REF: Add A Changeset To A Changegroup ** METHOD: sqlite3_changegroup @@ -11791,13 +11959,18 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); ** If the new changeset contains changes to a table that is already present ** in the changegroup, then the number of columns and the position of the ** primary key columns for the table must be consistent. If this is not the -** case, this function fails with SQLITE_SCHEMA. If the input changeset -** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is -** returned. Or, if an out-of-memory condition occurs during processing, this -** function returns SQLITE_NOMEM. In all cases, if an error occurs the state -** of the final contents of the changegroup is undefined. +** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup +** object has been configured with a database schema using the +** sqlite3changegroup_schema() API, then it is possible to combine changesets +** with different numbers of columns for a single table, provided that +** they are otherwise compatible. ** -** If no error occurs, SQLITE_OK is returned. +** If the input changeset appears to be corrupt and the corruption is +** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition +** occurs during processing, this function returns SQLITE_NOMEM. +** +** In all cases, if an error occurs the state of the final contents of the +** changegroup is undefined. If no error occurs, SQLITE_OK is returned. */ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); @@ -12062,10 +12235,17 @@ SQLITE_API int sqlite3changeset_apply_v2( **
  • an insert change if all fields of the conflicting row match ** the row being inserted. ** +** +**
    SQLITE_CHANGESETAPPLY_FKNOACTION
    +** If this flag it set, then all foreign key constraints in the target +** database behave as if they were declared with "ON UPDATE NO ACTION ON +** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL +** or SET DEFAULT. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 #define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 +#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008 /* ** CAPI3REF: Constants Passed To The Conflict Handler diff --git a/src/Makefile b/src/Makefile index da182fc3..ce2a4d38 100644 --- a/src/Makefile +++ b/src/Makefile @@ -64,7 +64,6 @@ EUAPI_OBJS = \ $(OBJD)\eu_hex.obj \ $(OBJD)\eu_scintilla.obj \ $(OBJD)\eu_encoding.obj \ - $(OBJD)\eu_encoding_utf8.obj \ $(OBJD)\eu_registry.obj \ $(OBJD)\eu_file.obj \ $(OBJD)\eu_treebar.obj \ @@ -217,7 +216,5 @@ $(OBJD)\eu_favorites.obj : eu_favorites.c eu_favorites.h frame $(OBJD)\eu_settings.obj : eu_settings.c eu_settings.h framework.h $(OBJD)\eu_hintctl.obj : eu_hintctl.c eu_hintctl.h framework.h $(OBJD)\eu_xmlist.obj : eu_xmlist.c eu_xmlist.h framework.h -$(OBJD)\eu_encoding_utf8.obj : eu_encoding_utf8.c eu_encoding_utf8.h framework.h - $(CC) $(API_CLFGAS) -Fd$(BIND)\euapi.pdb -Fo$(OBJD)\ $(MAVX2) -c eu_encoding_utf8.c $(OBJD)\resource.res : skylark.rc targetver.h skylark.exe.manifest $(ROOT)\resources\*.bmp $(RC) $(RFLAGS) -Fo$@ skylark.rc diff --git a/src/eu_api.c b/src/eu_api.c index 499c2043..02025c0e 100644 --- a/src/eu_api.c +++ b/src/eu_api.c @@ -28,7 +28,6 @@ #endif #include "framework.h" -#include "eu_encoding_utf8.h" #define CHAR_IN_RANGE(c, lower, upper) (((c) >= (lower)) && ((c) <= (upper))) #define CHAR_IS_LATIN(c) ((c) <= 0x7F) @@ -143,8 +142,9 @@ static eue_code eue_coding[] = {IDM_OTHER_2 , "MACCYRILLIC"} , {IDM_OTHER_3 , "MACCENTRALEUROPE"} , {IDM_OTHER_ANSI , "ANSI"} , - {IDM_OTHER_BIN , "Binary encoding"} , - {IDM_UNKNOWN , "Unknown encoding"} , + {IDM_OTHER_BIN , "Binary Code"} , + {IDM_OTHER_PLUGIN, "Plugins Code"} , + {IDM_UNKNOWN , "Unknown Code"} , {0 , NULL} }; @@ -1303,7 +1303,7 @@ eu_iconv_full_text(const TCHAR *file_name, const char *from_desc, const char *ds size_t len = 0; uint8_t *data = NULL; struct _stat st = {0}; - size_t buf_len = BUFF_SIZE; + size_t buf_len = BUFF_8M; if ((fp = _tfopen(file_name, _T("rb"))) == NULL) { return false; @@ -1314,7 +1314,7 @@ eu_iconv_full_text(const TCHAR *file_name, const char *from_desc, const char *ds fclose(fp); return false; } - if (st.st_size < BUFF_SIZE) + if (st.st_size < BUFF_8M) { buf_len = (size_t)st.st_size; } @@ -1370,11 +1370,11 @@ eu_try_encoding(uint8_t *buffer, size_t len, bool is_file, const TCHAR *file_nam else if (STR_NOT_NUL(file_name) && on_doc_get_type(file_name)) { // 如果是支持高亮的文件类型, 跳过二进制检测 nobinary = true; - read_len = eu_int_cast(len > BUFF_SIZE ? BUFF_SIZE : len); + read_len = eu_int_cast(len > BUFF_8M ? BUFF_8M : len); } else { - read_len = eu_int_cast(len > BUFF_SIZE ? BUFF_SIZE : len); + read_len = eu_int_cast(len > BUFF_8M ? BUFF_8M : len); } if (!(type = is_plan_file(checkstr, read_len, nobinary))) { @@ -1427,7 +1427,7 @@ eu_try_encoding(uint8_t *buffer, size_t len, bool is_file, const TCHAR *file_nam // GB18030! type = IDM_ANSI_12; } - else if (on_encoding_validate_utf8((const char *)checkstr, read_len)) + else if (on_encoding_validate_utf8(checkstr)) { eu_logmsg("Maybe UTF-8!\n"); type = obj->bom?IDM_UNI_UTF8B:IDM_UNI_UTF8; @@ -1450,7 +1450,7 @@ eu_try_encoding(uint8_t *buffer, size_t len, bool is_file, const TCHAR *file_nam } else if (_strnicmp(obj->encoding, "ISO-8859-", 9) == 0) { - if (on_encoding_validate_utf8((const char *)checkstr, read_len)) + if (on_encoding_validate_utf8(checkstr)) { eu_logmsg("Not iso encode, it's maybe UTF-8!\n"); type = obj->bom?IDM_UNI_UTF8B:IDM_UNI_UTF8; @@ -1486,7 +1486,7 @@ eu_try_encoding(uint8_t *buffer, size_t len, bool is_file, const TCHAR *file_nam } else if (obj->confidence < CHECK_2ND) { - if (on_encoding_validate_utf8((const char *)checkstr, read_len)) + if (on_encoding_validate_utf8(checkstr)) { eu_logmsg("we reconfirm that's UTF-8!\n"); type = obj->bom?IDM_UNI_UTF8B:IDM_UNI_UTF8; @@ -1803,8 +1803,8 @@ eu_free_config(void) g_config->m_customize[i].hbmp = 0; } } - free(g_config); - g_config = NULL; + free(g_config); + g_config = NULL; } } @@ -1965,6 +1965,7 @@ eu_save_config(void) "block_fold_visiable = %s\n" "tabs_tip_show_enable = %s\n" "code_hint_show_enable = %s\n" + "tab_split_show = %s\n" "tab_close_way = %d\n" "tab_close_draw = %d\n" "tab_new_way = %d\n" @@ -2101,6 +2102,7 @@ eu_save_config(void) g_config->block_fold?"true":"false", g_config->m_tab_tip?"true":"false", g_config->m_code_hint?"true":"false", + g_config->m_tab_split?"true":"false", g_config->m_close_way, g_config->m_close_draw, g_config->m_new_way, @@ -2137,7 +2139,7 @@ eu_save_config(void) g_config->eu_print.rect.right, g_config->eu_print.rect.bottom, g_config->eu_titlebar.icon?"true":"false", - g_config->eu_titlebar.name?"true":"false", + g_config->eu_titlebar.name||util_under_wine()?"true":"false", g_config->eu_titlebar.path?"true":"false", g_config->m_hyperlink?"true":"false", g_config->m_limit, @@ -2440,11 +2442,11 @@ void eu_lua_calltip(const char *pstr) { eu_tabpage *p = NULL; - if (pstr && (p = on_tabpage_focus_at()) && !p->hex_mode && !p->pmod) + if (pstr && (p = on_tabpage_focus_at()) && !TAB_HEX_MODE(p) && !p->pmod) { const sptr_t end = eu_sci_call(p, SCI_GETSELECTIONEND, 0, 0); eu_sci_call(p, SCI_SETEMPTYSELECTION, end, 0); - if (stricmp(pstr, "NaN") == 0 || stricmp(pstr, "INFINITY") == 0) + if (stricmp(pstr, "NaN") == 0 || stricmp(pstr, "INFINITY") == 0 || stricmp(pstr, "-INFINITY") == 0) { eu_sci_call(p, SCI_CALLTIPSHOW, end, (sptr_t) pstr); } @@ -2964,6 +2966,17 @@ eu_win10_or_later(void) return (uint32_t)-1; } +const bool +eu_win11_or_later(void) +{ + uint32_t patch = eu_win10_or_later(); + if (patch != (uint32_t)-1) + { + return (patch >= 22000) && (!util_under_wine()); + } + return false; +} + const int eu_theme_index(void) { @@ -3030,3 +3043,44 @@ eu_te_compile(const char *expression, const te_variable *variables, int var_coun { return (void *)te_compile(expression, variables, var_count, error); } + +void +eu_wine_dotool(void) +{ + TCHAR *plugin = NULL; + if (util_under_wine() && (plugin = util_winexy_tool())) + { + eu_new_process(plugin, NULL, NULL, 0, NULL); + free(plugin); + } +} + +bool +eu_under_wine(void) +{ + return util_under_wine(); +} + +bool +eu_which(const char *path) +{ + bool ret = false; + TCHAR *u16_path = NULL; + if (STR_NOT_NUL(path) && (u16_path = eu_utf8_utf16(path, NULL))) + { + TCHAR *exist = util_which(u16_path); + if (exist) + { + ret = true; + free(exist); + } + free(u16_path); + } + return ret; +} + +bool +eu_dark_enable(void) +{ + return on_dark_enable(); +} diff --git a/src/eu_api.h b/src/eu_api.h index 5c63e22f..fa9c94c3 100644 --- a/src/eu_api.h +++ b/src/eu_api.h @@ -105,9 +105,15 @@ #ifndef VALUE_LEN #define VALUE_LEN 4096 #endif - +#ifndef MAX_ACCELS #define MAX_ACCELS 200 +#endif + +#define BUFF_32K 0x8000 // 32K #define BUFF_64K 0x10000 +#define BUFF_8M 0x800000 // 8M +#define BUFF_32M 0x2000000 // 32M +#define BUFF_128M 0x8000000 // 128M #define BUFF_200M 0xc800000 #ifndef WM_COPYGLOBALDATA @@ -122,6 +128,8 @@ #define TBCTL_LIST_SUBID 0x43 #define STATUSBAR_SUBID 0x44 +#define DARK_THEME_APPLY 1 + // Custom message #define HVM_SETEXTENDEDSTYLE (WM_USER + 100) #define HVM_SETITEMCOUNT (WM_USER + 101) @@ -283,6 +291,13 @@ enum INDIC_SKYLARK_HYPER_U }; +enum +{ + TYPES_TEXT = 0, + TYPES_HEX, + TYPES_PLUGIN +}; + typedef enum _UPDATE_STATUS { VERSION_LATEST = 0, @@ -463,6 +478,7 @@ struct eu_config bool block_fold; bool m_tab_tip; bool m_code_hint; + bool m_tab_split; int m_close_way; int m_close_draw; @@ -589,11 +605,15 @@ EU_EXT_CLASS void eu_get_folder_history(sql3_callback pfunc); // eu_api.c EU_EXT_CLASS bool eu_touch(LPCTSTR path); EU_EXT_CLASS bool eu_exist_path(const char *path); +EU_EXT_CLASS bool eu_which(const char *path); EU_EXT_CLASS bool eu_mk_dir(LPCTSTR dir); EU_EXT_CLASS bool eu_exist_dir(LPCTSTR path); EU_EXT_CLASS bool eu_exist_file(LPCTSTR path); EU_EXT_CLASS bool eu_exist_libcurl(void); EU_EXT_CLASS bool eu_exist_libssl(void); +EU_EXT_CLASS bool eu_under_wine(void); +EU_EXT_CLASS bool eu_dark_enable(void); +EU_EXT_CLASS void eu_wine_dotool(void); EU_EXT_CLASS LPTSTR eu_suffix_strip(TCHAR *path); EU_EXT_CLASS LPTSTR eu_rand_str(TCHAR *str, const int len); EU_EXT_CLASS char *eu_str_replace(char *in, const size_t in_size, const char *pattern, const char *by); @@ -620,6 +640,7 @@ EU_EXT_CLASS void eu_api_release(void); EU_EXT_CLASS const int eu_theme_index(void); EU_EXT_CLASS const uint32_t eu_win10_or_later(void); +EU_EXT_CLASS const bool eu_win11_or_later(void); EU_EXT_CLASS char *eu_strcasestr(const char *haystack, const char *needle); EU_EXT_CLASS const char *eu_query_encoding_name(int code); EU_EXT_CLASS const uint8_t *eu_memstr(const uint8_t *haystack, const char *needle, size_t size); @@ -703,8 +724,6 @@ EU_EXT_CLASS void eu_about_command(void); EU_EXT_CLASS HWND eu_module_hwnd(void); EU_EXT_CLASS void eu_close_edit(void); EU_EXT_CLASS HWND eu_create_main_window(HINSTANCE instance); -EU_EXT_CLASS bool eu_create_toolbar(HWND hwnd); -EU_EXT_CLASS bool eu_create_statusbar(HWND hwnd); EU_EXT_CLASS void eu_create_fullscreen(HWND hwnd); EU_EXT_CLASS int eu_before_proc(MSG *p_msg); EU_EXT_CLASS uint32_t eu_get_dpi(HWND hwnd); @@ -729,7 +748,7 @@ EU_EXT_CLASS void share_unmap(LPVOID memory); EU_EXT_CLASS void share_close(HANDLE handle); EU_EXT_CLASS HANDLE share_open(uint32_t dw_access, LPCTSTR name); EU_EXT_CLASS bool share_envent_create(void); -EU_EXT_CLASS void share_envent_set(bool signaled); +EU_EXT_CLASS void share_envent_set(const bool signaled); EU_EXT_CLASS void share_envent_close(void); EU_EXT_CLASS void share_envent_release(void); EU_EXT_CLASS HANDLE share_envent_open_file_sem(void); diff --git a/src/eu_changes.c b/src/eu_changes.c index 674061ae..8337bb85 100644 --- a/src/eu_changes.c +++ b/src/eu_changes.c @@ -383,7 +383,7 @@ on_changes_window(HWND hwnd) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && !p->is_blank && !p->fs_server.networkaddr[0] && p->st_mtime != util_last_time(p->pathfile)) + if (p && !TAB_HEX_MODE(p) && !p->is_blank && !p->fs_server.networkaddr[0] && p->st_mtime != util_last_time(p->pathfile)) { on_changes_click_sci(on_tabpage_focus_at()); on_tabpage_selection(p, index); diff --git a/src/eu_code.c b/src/eu_code.c index e19c7efa..a57860ce 100644 --- a/src/eu_code.c +++ b/src/eu_code.c @@ -57,7 +57,7 @@ on_doc_redis_config(char *out, int len, const char *str) void on_code_do_fold(eu_tabpage *pnode, int code, sptr_t line_number, bool do_wrap) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { sptr_t fold_line, line = 0; if (line_number >= 0) @@ -129,7 +129,7 @@ on_code_do_fold(eu_tabpage *pnode, int code, sptr_t line_number, bool do_wrap) void on_code_switch_fold(eu_tabpage *pnode, sptr_t line_number) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { const sptr_t pos = eu_sci_call(pnode, SCI_GETCURRENTPOS, 0, 0); sptr_t line = line_number >= 0 ? line_number : eu_sci_call(pnode, SCI_LINEFROMPOSITION, pos, 0); @@ -151,7 +151,7 @@ on_code_switch_fold(eu_tabpage *pnode, sptr_t line_number) void on_code_block_contract_all(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_FOLDALL, SC_FOLDACTION_CONTRACT, 0); if (document_map_initialized && pnode->map_show) @@ -171,7 +171,7 @@ on_code_block_contract_all(eu_tabpage *pnode) void on_code_block_expand_all(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_FOLDALL, SC_FOLDACTION_EXPAND, 0); if (document_map_initialized && pnode->map_show) @@ -210,7 +210,7 @@ on_code_set_complete_chars(eu_tabpage *pnode) void on_code_insert_config(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { const char *eol_str = on_encoding_get_eol(pnode); char dbase_config[MAX_BUFFER+1] = {0}; diff --git a/src/eu_config.c b/src/eu_config.c index b35bb78f..0efe8a67 100644 --- a/src/eu_config.c +++ b/src/eu_config.c @@ -184,24 +184,25 @@ static unsigned __stdcall on_config_load_file(void *lp) { int err = 0; + size_t vec_size = 0; cvector_vector_type(file_backup) vbak = NULL; if (eu_get_config()->m_session) - { - err = on_sql_do_session("SELECT * FROM skylark_session;", on_config_parser_bakup, (void *)&vbak); // 这里又导致工作目录变更了 + { // on_config_parser_bakup导致工作目录变更 + err = on_sql_do_session("SELECT * FROM skylark_session;", on_config_parser_bakup, (void *)&vbak); } else { err = on_sql_do_session("SELECT * FROM skylar_ver;", NULL, NULL); } on_config_open_args(&vbak); - if (cvector_size(vbak) < 1) + if ((vec_size = cvector_size(vbak)) < 1) { file_backup bak = {0}; share_send_msg(&bak); } else { - for (size_t i = 0; i < cvector_size(vbak); ++i) + for (size_t i = 0; i < vec_size; ++i) { if (vbak[i].rel_path[0] || vbak[i].bak_path[0]) { diff --git a/src/eu_document_map.c b/src/eu_document_map.c index 49e0ac35..a5d0458a 100644 --- a/src/eu_document_map.c +++ b/src/eu_document_map.c @@ -355,7 +355,7 @@ on_map_create_static_dlg(HWND parent) if (!hwnd_document_static) { bool win10 = util_os_version() >= 1000; - if (win10) + if (win10 && !util_under_wine()) { hwnd_document_static = CreateDialogParam(eu_module_handle(), MAKEINTRESOURCE(IDD_VIEWZONE), parent, on_map_static_proc, 0); } diff --git a/src/eu_edit.c b/src/eu_edit.c index 334e5c7e..2e0063bb 100644 --- a/src/eu_edit.c +++ b/src/eu_edit.c @@ -47,7 +47,7 @@ on_edit_undo(eu_tabpage *pnode) for (int i = 0; i < count; ++i) { eu_tabpage *p = on_tabpage_get_ptr(v[i]); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { eu_sci_call(p, SCI_UNDO, 0, 0); } @@ -68,7 +68,7 @@ on_edit_redo(eu_tabpage *pnode) for (int i = 0; i < count; ++i) { eu_tabpage *p = on_tabpage_get_ptr(v[i]); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { eu_sci_call(p, SCI_REDO, 0, 0); } @@ -93,7 +93,7 @@ on_edit_copy_text(eu_tabpage *pnode) { if (pnode) { - if (pnode->hex_mode) + if (TAB_HEX_MODE(pnode)) { eu_sci_call(pnode, WM_COPY, 0, 0); } @@ -125,7 +125,7 @@ on_edit_delete_text(eu_tabpage *pnode) void on_edit_cut_line(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_LINECUT, 0, 0); } @@ -134,7 +134,7 @@ on_edit_cut_line(eu_tabpage *pnode) void on_edit_copy_line(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { char *text = util_strdup_line(pnode, -1, NULL); if (text) @@ -153,7 +153,7 @@ on_edit_copy_line(eu_tabpage *pnode) void on_edit_line_up(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_MOVESELECTEDLINESUP, 0, 0); } @@ -162,7 +162,7 @@ on_edit_line_up(eu_tabpage *pnode) void on_edit_line_down(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_MOVESELECTEDLINESDOWN, 0, 0); // 确保所选内容在视图中可见 @@ -230,7 +230,7 @@ on_edit_incremental_clipborad(eu_tabpage *pnode) void on_edit_rtf_clipborad(const HWND hwnd, eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { char *prtf = NULL; const sptr_t start = eu_sci_call(pnode, SCI_GETSELECTIONSTART, 0, 0); @@ -274,7 +274,7 @@ on_edit_rtf_clipborad(const HWND hwnd, eu_tabpage *pnode) void on_edit_swap_clipborad(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->plugin && eu_sci_call(pnode, SCI_CANPASTE, 0, 0)) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->plugin && eu_sci_call(pnode, SCI_CANPASTE, 0, 0)) { char *buf = NULL; wchar_t *pbuf = NULL; @@ -392,6 +392,33 @@ on_edit_execute(eu_tabpage *pnode, const TCHAR *path) CloseHandle(eu_new_process(cmd, NULL, NULL, 2, NULL)); } +static bool +on_edit_exist_bc(const wchar_t *path, const wchar_t *name) +{ + if (STR_NOT_NUL(name)) + { + return wcsnicmp(name, L"Beyond Compare", wcslen(L"Beyond Compare")) == 0; + } + else if (STR_NOT_NUL(path)) + { + const wchar_t *p = wcsrchr(path, L'\\'); + const wchar_t *bname = L"bcompare"; + if (!p) + { + p = wcsrchr(path, L'/'); + } + if (p) + { + return wcsnicmp(p + 1, bname, wcslen(bname)) == 0; + } + else + { + return wcsnicmp(path, bname, wcslen(bname)) == 0; + } + } + return false; +} + static void on_edit_compare(const wchar_t *path, const wchar_t **pvec, const bool hex) { @@ -400,20 +427,19 @@ on_edit_compare(const wchar_t *path, const wchar_t **pvec, const bool hex) wchar_t *plugin = NULL; wchar_t *cmd_exec = NULL; wchar_t name[MAX_PATH] = {0}; - wchar_t unix_path[MAX_PATH] = {0}; bool wine = util_under_wine(); int count = eu_int_cast(cvector_size(pvec)); const int len = (count + 1) * (MAX_PATH + 1); util_product_name(path, name, MAX_PATH - 1); - if ((plugin = util_winexy_get()) && (cmd_exec = (wchar_t *)calloc(sizeof(wchar_t), len + 1))) + if ((plugin = util_winexy_hide()) && (cmd_exec = (wchar_t *)calloc(sizeof(wchar_t), len + 1))) { if (!hex) { _snwprintf(cmd_exec, len, L"%s \"%s\" ", plugin, path); } - else if (wcsnicmp(name, L"Beyond Compare", wcslen(L"Beyond Compare")) == 0) + else if (on_edit_exist_bc(path, name)) { - _snwprintf(cmd_exec, len, L"%s \"%s\" %s ", plugin, path, L"/fv=\"Hex Compare\""); + _snwprintf(cmd_exec, len, L"%s \"%s\" %s ", plugin, path, wine ? L"-fv=\\\"Hex Compare\\\"" : L"/fv=\"Hex Compare\""); } else if (wcsnicmp(name, L"WinMerge", wcslen(L"WinMerge")) == 0) { @@ -430,33 +456,32 @@ on_edit_compare(const wchar_t *path, const wchar_t **pvec, const bool hex) } for (int i = 0; i < count; ++i) { + wchar_t unix_path[MAX_PATH] = {0}; if (i == count - 1) { - wcsncat(cmd_exec, L"\"", len); + wcsncat(cmd_exec, wine ? L"\\\"" : L"\"", len); if (wine && util_get_unix_file_name(pvec[i], unix_path, MAX_PATH)) { wcsncat(cmd_exec, unix_path, len); - memset(unix_path, 0, sizeof(unix_path)); } else { wcsncat(cmd_exec, pvec[i], len); } - wcsncat(cmd_exec, L"\"", len); + wcsncat(cmd_exec, wine ? L"\\\"" : L"\"", len); } else { - wcsncat(cmd_exec, L"\"", len); + wcsncat(cmd_exec, wine ? L"\\\"" : L"\"", len); if (wine && util_get_unix_file_name(pvec[i], unix_path, MAX_PATH)) { wcsncat(cmd_exec, unix_path, len); - memset(unix_path, 0, sizeof(unix_path)); } else { wcsncat(cmd_exec, pvec[i], len); } - wcsncat(cmd_exec, L"\" ", len); + wcsncat(cmd_exec, wine ? L"\\\" " : L"\" ", len); } } CloseHandle(eu_new_process(cmd_exec, NULL, NULL, 2, NULL)); @@ -535,7 +560,7 @@ on_edit_push_compare(void) void on_edit_convert_slash(eu_tabpage *pnode, const bool slash) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { char *buf = NULL; const sptr_t start = eu_sci_call(pnode, SCI_GETSELECTIONSTART, 0, 0); @@ -588,7 +613,7 @@ on_edit_convert_slash(eu_tabpage *pnode, const bool slash) void on_edit_delete_line(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_LINEDELETE, 0, 0); } @@ -625,7 +650,7 @@ on_edit_add_array(eu_tabpage *pnode, char *pbuf, char *strarray[], int count) void on_edit_delete_dups(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { char *buf = NULL; char **ptext = NULL; @@ -715,7 +740,7 @@ on_edit_delete_dups(eu_tabpage *pnode) void on_edit_line_transpose(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_LINETRANSPOSE, 0, 0); } @@ -755,25 +780,17 @@ count_line_space(eu_tabpage *pnode, sptr_t start, sptr_t end, bool header) return count; } -static bool -do_delete_space(eu_tabpage *pnode, sptr_t start, sptr_t end, bool header) +static void +do_delete_space(eu_tabpage *pnode, const sptr_t start, const sptr_t end, const bool header) { eu_sci_call(pnode, SCI_BEGINUNDOACTION, 0, 0); for (sptr_t line = start; line <= end; ++line) { - sptr_t start_pos, end_pos, str_len, del_len; - start_pos = eu_sci_call(pnode, SCI_POSITIONFROMLINE, line, 0); - end_pos = eu_sci_call(pnode, SCI_GETLINEENDPOSITION, line, 0); - str_len = end_pos - start_pos; - if (str_len == 0) - { - continue; - } - else - { - del_len = count_line_space(pnode, start_pos, end_pos, header); - } - if (del_len > 0) + sptr_t del_len = 0; + sptr_t start_pos = eu_sci_call(pnode, SCI_POSITIONFROMLINE, line, 0); + sptr_t end_pos = eu_sci_call(pnode, SCI_GETLINEENDPOSITION, line, 0); + sptr_t str_len = end_pos - start_pos; + if (str_len > 0 && (del_len = count_line_space(pnode, start_pos, end_pos, header)) > 0) { if (header) { @@ -786,13 +803,12 @@ do_delete_space(eu_tabpage *pnode, sptr_t start, sptr_t end, bool header) } } eu_sci_call(pnode, SCI_ENDUNDOACTION, 0, 0); - return true; } void on_edit_delete_line_header_white(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { sptr_t start_line, end_line; util_effect_line(pnode, &start_line, &end_line); @@ -803,7 +819,7 @@ on_edit_delete_line_header_white(eu_tabpage *pnode) void on_edit_delete_line_tail_white(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { sptr_t start_line, end_line; util_effect_line(pnode, &start_line, &end_line); @@ -822,7 +838,7 @@ on_edit_delete_line_header_all(eu_tabpage *pnode) for (int i = 0; i < count; ++i) { eu_tabpage *p = on_tabpage_get_ptr(v[i]); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { do_delete_space(p, 1, eu_sci_call(p, SCI_GETLINECOUNT, 0, 0), true); } @@ -842,7 +858,7 @@ on_edit_delete_line_tail_all(eu_tabpage *pnode) for (int i = 0; i < count; ++i) { eu_tabpage *p = on_tabpage_get_ptr(v[i]); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { do_delete_space(p, 1, eu_sci_call(p, SCI_GETLINECOUNT, 0, 0), false); } @@ -871,8 +887,8 @@ space_in_line(eu_tabpage *pnode, sptr_t start, sptr_t end) return res; } -static bool -do_delete_lines(eu_tabpage *pnode, sptr_t start, sptr_t end, bool white_chars) +static void +do_delete_lines(eu_tabpage *pnode, sptr_t start, sptr_t end, const bool white_chars) { eu_sci_call(pnode, SCI_BEGINUNDOACTION, 0, 0); for (sptr_t line = start; line <= end; ++line) @@ -890,7 +906,6 @@ do_delete_lines(eu_tabpage *pnode, sptr_t start, sptr_t end, bool white_chars) } } eu_sci_call(pnode, SCI_ENDUNDOACTION, 0, 0); - return true; } void @@ -904,7 +919,7 @@ on_edit_delete_all_empty_lines(eu_tabpage *pnode) for (int i = 0; i < count; ++i) { eu_tabpage *p = on_tabpage_get_ptr(v[i]); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { do_delete_lines(p, 0, eu_sci_call(p, SCI_GETLINECOUNT, 0, 0), true); } @@ -916,7 +931,7 @@ on_edit_delete_all_empty_lines(eu_tabpage *pnode) void on_edit_join_line(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { sptr_t pos = eu_sci_call(pnode, SCI_GETCURRENTPOS, 0, 0); sptr_t current_line = eu_sci_call(pnode, SCI_LINEFROMPOSITION, pos, 0); @@ -928,7 +943,7 @@ on_edit_join_line(eu_tabpage *pnode) } static void -do_toggle_case(eu_tabpage *pnode, bool do_uppercase, bool do_line, bool first) +do_toggle_case(eu_tabpage *pnode, const bool do_uppercase, const bool do_line, const bool first) { sptr_t sel_start = 0; sptr_t sel_end = 0; @@ -984,7 +999,7 @@ do_toggle_case(eu_tabpage *pnode, bool do_uppercase, bool do_line, bool first) void on_edit_lower(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { bool has_selection = false; sptr_t sel_start = eu_sci_call(pnode, SCI_GETSELECTIONSTART, 0, 0); @@ -1003,7 +1018,7 @@ on_edit_lower(eu_tabpage *pnode) void on_edit_upper(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { bool has_selection = false; sptr_t sel_start = eu_sci_call(pnode, SCI_GETSELECTIONSTART, 0, 0); @@ -1020,7 +1035,7 @@ on_edit_upper(eu_tabpage *pnode) } static void -do_selection_case(eu_tabpage *pnode, bool sentence) +do_selection_case(eu_tabpage *pnode, const bool sentence) { sptr_t sel_start = eu_sci_call(pnode, SCI_GETSELECTIONSTART, 0, 0); sptr_t sel_end = eu_sci_call(pnode, SCI_GETSELECTIONEND, 0, 0); @@ -1074,7 +1089,7 @@ do_selection_case(eu_tabpage *pnode, bool sentence) void on_edit_sentence_upper(eu_tabpage *pnode, const bool sentence) { - if (pnode && !pnode->hex_mode && !pnode->pmod && !eu_sci_call(pnode, SCI_SELECTIONISRECTANGLE, 0, 0)) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod && !eu_sci_call(pnode, SCI_SELECTIONISRECTANGLE, 0, 0)) { if (!eu_sci_call(pnode, SCI_GETSELECTIONEMPTY, 0, 0)) { @@ -1088,7 +1103,7 @@ on_edit_sentence_upper(eu_tabpage *pnode, const bool sentence) } void -on_edit_selection(eu_tabpage *pnode, int type) +on_edit_selection(eu_tabpage *pnode, const int type) { size_t len = 0; char *text = NULL; @@ -1222,7 +1237,7 @@ on_edit_base64_enc(eu_tabpage *pnode) size_t out_len; char *sel_text = NULL; char *out_text = NULL; - if (!pnode || pnode->hex_mode || pnode->plugin) + if (!pnode || TAB_HEX_MODE(pnode) || pnode->plugin) { return 0; } @@ -1289,7 +1304,7 @@ on_edit_base64_dec(eu_tabpage *pnode) { return EUE_TAB_NULL; } - if (pnode->hex_mode || pnode->plugin) + if (TAB_HEX_MODE(pnode) || pnode->plugin) { return EUE_UNKOWN_ERR; } @@ -1330,7 +1345,7 @@ on_edit_md5(eu_tabpage *pnode) { return EUE_TAB_NULL; } - if (pnode->hex_mode || pnode->plugin) + if (TAB_HEX_MODE(pnode) || pnode->plugin) { return EUE_UNKOWN_ERR; } @@ -1364,7 +1379,7 @@ on_edit_sha1(eu_tabpage *pnode) { return EUE_TAB_NULL; } - if (pnode->hex_mode || pnode->plugin) + if (TAB_HEX_MODE(pnode) || pnode->plugin) { return EUE_UNKOWN_ERR; } @@ -1398,7 +1413,7 @@ on_edit_sha256(eu_tabpage *pnode) { return EUE_TAB_NULL; } - if (pnode->hex_mode || pnode->plugin) + if (TAB_HEX_MODE(pnode) || pnode->plugin) { return EUE_UNKOWN_ERR; } @@ -1431,7 +1446,7 @@ on_edit_descbc_enc(eu_tabpage *pnode) char *out_text = NULL; char *text_exp = NULL; char key[24 + 1] = { 0 }; - if (!pnode || pnode->hex_mode || pnode->plugin) + if (!pnode || TAB_HEX_MODE(pnode) || pnode->plugin) { return 0; } @@ -1490,7 +1505,7 @@ on_edit_descbc_dec(eu_tabpage *pnode) char *input_text = NULL; char *out_text = NULL; char key[24 + 1] = { 0 }; - if (!pnode || pnode->hex_mode || pnode->plugin) + if (!pnode || TAB_HEX_MODE(pnode) || pnode->plugin) { return 0; } @@ -1865,7 +1880,7 @@ on_edit_comment_line(eu_tabpage *pnode) { return 1; } - if (pnode->hex_mode || pnode->plugin) + if (TAB_HEX_MODE(pnode) || pnode->plugin) { return 0; } @@ -1979,7 +1994,7 @@ on_edit_comment_stream(eu_tabpage *pnode) { return 1; } - if (pnode->hex_mode || pnode->plugin) + if (TAB_HEX_MODE(pnode) || pnode->plugin) { return 0; } @@ -2085,7 +2100,7 @@ on_edit_comment_stream(eu_tabpage *pnode) int on_edit_convert_eols(eu_tabpage *pnode, int eol_mode) { - if (pnode && !pnode->hex_mode && !pnode->pmod && (eu_sci_call(pnode, SCI_GETEOLMODE, 0, 0) != eol_mode)) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod && (eu_sci_call(pnode, SCI_GETEOLMODE, 0, 0) != eol_mode)) { eu_sci_call(pnode, SCI_SETEOLMODE, eol_mode, 0); eu_sci_call(pnode, SCI_BEGINUNDOACTION, 0, 0); @@ -2094,6 +2109,7 @@ on_edit_convert_eols(eu_tabpage *pnode, int eol_mode) eu_sci_call(pnode, SCI_ENDUNDOACTION, 0, 0); _snprintf(pnode->eols_undo_str, QW_SIZE-1, "%s=%d=%d", EOLS_UNDO_DESC, pnode->eol, eol_mode); pnode->eol = eol_mode; + on_file_filedb_update(pnode); return 0; } return 1; @@ -2102,7 +2118,7 @@ on_edit_convert_eols(eu_tabpage *pnode, int eol_mode) int on_edit_convert_coding(eu_tabpage *pnode, int new_code) { - if (pnode && !pnode->hex_mode && !pnode->pmod && pnode->codepage != new_code) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod && pnode->codepage != new_code) { _snprintf(pnode->icon_undo_str, QW_SIZE-1, "%s=%d=%d", ICON_UNDO_DESC, pnode->codepage, new_code); pnode->codepage = new_code; @@ -2111,6 +2127,7 @@ on_edit_convert_coding(eu_tabpage *pnode, int new_code) eu_sci_call(pnode, SCI_DELETERANGE, 0, strlen(pnode->icon_undo_str)); eu_sci_call(pnode, SCI_ADDUNDOACTION, ICONV_UNDO, 0); eu_sci_call(pnode, SCI_ENDUNDOACTION, 0, 0); + on_file_filedb_update(pnode); return 0; } return 1; @@ -2119,7 +2136,7 @@ on_edit_convert_coding(eu_tabpage *pnode, int new_code) void on_edit_undo_iconv(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { int old_codepage = IDM_UNKNOWN; int new_codepage = IDM_UNKNOWN; @@ -2129,7 +2146,7 @@ on_edit_undo_iconv(eu_tabpage *pnode) memset(pnode->pre_context, 0, sizeof(pnode->pre_context)); _snprintf(pnode->icon_undo_str, QW_SIZE-1, "%s=%d=%d", ICON_UNDO_DESC, new_codepage, old_codepage); on_encoding_set_bom_from_cp(pnode); - on_statusbar_update_coding(pnode, 0); + on_statusbar_update_coding(pnode); } } } @@ -2137,7 +2154,7 @@ on_edit_undo_iconv(eu_tabpage *pnode) void on_edit_undo_eol(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { int old_eol = -1; int new_eol = -1; @@ -2186,7 +2203,7 @@ on_edit_sorting(eu_tabpage *p, int wm_id) for (int k = 0; k < count; ++k) { eu_tabpage *pnode = on_tabpage_get_ptr(v[k]); - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { int i = 0; int count = 0; @@ -2315,3 +2332,138 @@ on_edit_sorting(eu_tabpage *p, int wm_id) } cvector_freep(&v); } + +void +on_edit_bookmark_copy(eu_tabpage *pnode) +{ + char *p = NULL; + char *p1 = NULL; + wchar_t *ptext = NULL; + sptr_t line = LINE_NOT_FOUND; + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) + { + for (sptr_t i = 0, last = eu_sci_call(pnode, SCI_GETLINECOUNT, 0, 0); i < last; ++i) + { + if ((line = on_search_marker_next(pnode, i, last, MARGIN_BOOKMARK_MASKN)) != LINE_NOT_FOUND) + { + i = line; + if ((p1 = util_strdup_line(pnode, line, NULL))) + { + p = util_memdup(&p , p1); + free(p1); + if (!p) + { + eu_logmsg("Warning: p is null\n"); + break; + } + } + } + } + if (p && (ptext = eu_utf8_utf16(p, NULL))) + { + on_edit_push_clipboard(ptext); + } + eu_safe_free(p); + eu_safe_free(ptext); + } +} + +void +on_edit_bookmark_cut(eu_tabpage *pnode) +{ + char *p = NULL; + char *p1 = NULL; + wchar_t *ptext = NULL; + sptr_t line = LINE_NOT_FOUND; + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) + { + eu_sci_call(pnode, SCI_BEGINUNDOACTION, 0, 0); + for (sptr_t i = 0, last = eu_sci_call(pnode, SCI_GETLINECOUNT, 0, 0); i < last; ++i) + { + if ((line = on_search_marker_next(pnode, i, last, MARGIN_BOOKMARK_MASKN)) != LINE_NOT_FOUND) + { + if ((p1 = util_strdup_line(pnode, line, NULL))) + { + p = util_memdup(&p , p1); + free(p1); + if (!p) + { + break; + } + else + { + sptr_t start = eu_sci_call(pnode, SCI_POSITIONFROMLINE, line, 0); + sptr_t end = eu_sci_call(pnode, SCI_POSITIONFROMLINE, line + 1, 0); + if (end == LINE_NOT_FOUND) + { + end = eu_sci_call(pnode, SCI_GETLINEENDPOSITION, line, 0); + } + eu_sci_call(pnode, SCI_DELETERANGE, start, end - start); + eu_sci_call(pnode, SCI_MARKERDELETE, line, MARGIN_BOOKMARK_VALUE); + } + } + i = line - 1; + --last; + } + } + eu_sci_call(pnode, SCI_ENDUNDOACTION, 0, 0); + if (p && (ptext = eu_utf8_utf16(p, NULL))) + { + on_edit_push_clipboard(ptext); + } + eu_safe_free(p); + eu_safe_free(ptext); + } +} + +void +on_edit_bookmark_remove(eu_tabpage *pnode) +{ + sptr_t line = LINE_NOT_FOUND; + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) + { + eu_sci_call(pnode, SCI_BEGINUNDOACTION, 0, 0); + for (sptr_t i = 0, last = eu_sci_call(pnode, SCI_GETLINECOUNT, 0, 0); i < last; ++i) + { + if ((line = on_search_marker_next(pnode, i, last, MARGIN_BOOKMARK_MASKN)) != LINE_NOT_FOUND) + { + sptr_t start = eu_sci_call(pnode, SCI_POSITIONFROMLINE, line, 0); + sptr_t end = eu_sci_call(pnode, SCI_POSITIONFROMLINE, line + 1, 0); + if (end == LINE_NOT_FOUND) + { + end = eu_sci_call(pnode, SCI_GETLINEENDPOSITION, line, 0); + } + eu_sci_call(pnode, SCI_DELETERANGE, start, end - start); + eu_sci_call(pnode, SCI_MARKERDELETE, line, MARGIN_BOOKMARK_VALUE); + i = line - 1; + --last; + } + } + eu_sci_call(pnode, SCI_ENDUNDOACTION, 0, 0); + } +} + +void +on_edit_bookmark_reserve_remove(eu_tabpage *pnode) +{ + sptr_t line = LINE_NOT_FOUND; + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) + { + eu_sci_call(pnode, SCI_BEGINUNDOACTION, 0, 0); + for (sptr_t i = 0, last = eu_sci_call(pnode, SCI_GETLINECOUNT, 0, 0); i < last; ++i) + { + if (!(eu_sci_call(pnode, SCI_MARKERGET, i, 0) & MARGIN_BOOKMARK_MASKN)) + { + sptr_t start = eu_sci_call(pnode, SCI_POSITIONFROMLINE, i, 0); + sptr_t end = eu_sci_call(pnode, SCI_POSITIONFROMLINE, i + 1, 0); + if (end == LINE_NOT_FOUND) + { + end = eu_sci_call(pnode, SCI_GETLINEENDPOSITION, i, 0); + } + eu_sci_call(pnode, SCI_DELETERANGE, start, end - start); + --i, --last; + } + } + eu_sci_call(pnode, SCI_ENDUNDOACTION, 0, 0); + } +} diff --git a/src/eu_edit.h b/src/eu_edit.h index 8db8f193..94090376 100644 --- a/src/eu_edit.h +++ b/src/eu_edit.h @@ -30,8 +30,11 @@ #endif #define STR_IS_NUL(s) (s == NULL || *s == 0) #define STR_NOT_NUL(s) (s != NULL && *s != 0) +#define TAB_HEX_MODE(p) (p->hex_mode == TYPES_HEX) #define TAB_NOT_NUL(p) (eu_sci_call(p, SCI_GETLENGTH, 0, 0) > 0) #define TAB_NOT_BIN(p) (p->codepage != IDM_OTHER_BIN) +#define TAB_HAS_PDF(p) (p->codepage == IDM_OTHER_PLUGIN) +#define TAB_HAS_TXT(p) (!TAB_HEX_MODE(p) && !TAB_HAS_PDF(p)) #define EOLS_UNDO 101 #define ICONV_UNDO 102 @@ -67,7 +70,7 @@ void on_edit_join_line(eu_tabpage *pnode); void on_edit_lower(eu_tabpage *pnode); void on_edit_upper(eu_tabpage *pnode); void on_edit_sentence_upper(eu_tabpage *pnode, const bool sentence); -void on_edit_selection(eu_tabpage *pnode, int type); +void on_edit_selection(eu_tabpage *pnode, const int type); void on_edit_undo_eol(eu_tabpage *pnode); void on_edit_undo_iconv(eu_tabpage *pnode); void on_edit_sorting(eu_tabpage *p, int wm_id); @@ -75,6 +78,10 @@ void on_edit_push_compare(void); void on_edit_incremental_clipborad(eu_tabpage *pnode); void on_edit_rtf_clipborad(const HWND hwnd, eu_tabpage *pnode); void on_edit_convert_slash(eu_tabpage *pnode, const bool slash); +void on_edit_bookmark_copy(eu_tabpage *pnode); +void on_edit_bookmark_cut(eu_tabpage *pnode); +void on_edit_bookmark_remove(eu_tabpage *pnode); +void on_edit_bookmark_reserve_remove(eu_tabpage *pnode); int on_edit_base64_enc(eu_tabpage *pnode); int on_edit_base64_dec(eu_tabpage *pnode); diff --git a/src/eu_encoding.c b/src/eu_encoding.c index a8c712de..4b921d23 100644 --- a/src/eu_encoding.c +++ b/src/eu_encoding.c @@ -22,6 +22,27 @@ #define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) #define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) +#define GET_UTF8(val, GET_BYTE, ERROR) \ + val = (GET_BYTE); \ + { \ + uint32_t top = (val & 128) >> 1; \ + if ((val & 0xc0) == 0x80 || val >= 0xFE) \ + { \ + ERROR \ + } \ + while (val & top) \ + { \ + unsigned int tmp = (GET_BYTE)-128; \ + if (tmp >> 6) \ + { \ + ERROR \ + } \ + val = (val << 6) + tmp; \ + top <<= 5; \ + } \ + val &= (top << 1) - 1; \ + } \ + static bool is_cjk_converter(const char *encoding) { @@ -409,7 +430,7 @@ on_encoding_convert_internal_code(eu_tabpage *pnode, enc_back fn) int ret = 1; size_t len = 0; char *dst = NULL; - if (pnode && !pnode->hex_mode && !pnode->pmod && fn) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod && fn) { bool whole = false; char *ptxt = util_strdup_select(pnode, &len, 0); @@ -457,3 +478,27 @@ on_encoding_convert_internal_code(eu_tabpage *pnode, enc_back fn) } return ret; } + +bool +on_encoding_validate_utf8(const uint8_t *str) +{ + const uint8_t *byte; + uint32_t codepoint, min; + while (*str) + { + byte = str; + if ((*str >> 7) == 0) + { + ++str; + continue; + } + GET_UTF8(codepoint, *(byte++), return false;); + min = byte - str == 1 ? 0 : byte - str == 2 ? 0x80 : 1 << (5 * (byte - str) - 4); + if (codepoint < min || codepoint >= 0x110000 || (codepoint >= 0xD800 && codepoint <= 0xDFFF)) + { + return false; + } + str = byte; + } + return true; +} diff --git a/src/eu_encoding.h b/src/eu_encoding.h index 203046b3..b3ef185a 100644 --- a/src/eu_encoding.h +++ b/src/eu_encoding.h @@ -46,6 +46,7 @@ int on_encoding_line_mode(const char *str , size_t len); int on_encoding_set_bom(const uint8_t *buf, eu_tabpage *pnode); int on_encoding_convert_internal_code(eu_tabpage *pnode, enc_back fn); void on_encoding_set_bom_from_cp(eu_tabpage *pnode); +bool on_encoding_validate_utf8(const uint8_t *str); size_t on_encoding_do_iconv(euconv_t *icv, char *src, size_t *src_len, char **dst, size_t *plen); const char *on_encoding_get_eol(eu_tabpage *pnode); const int on_encoding_eol_char(eu_tabpage *pnode); diff --git a/src/eu_encoding_utf8.c b/src/eu_encoding_utf8.c deleted file mode 100644 index 1b05a08e..00000000 --- a/src/eu_encoding_utf8.c +++ /dev/null @@ -1,389 +0,0 @@ -// faster-utf8-validator -// -// Copyright (c) 2019 Zach Wegner -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// https://github.com/zwegner/faster-utf8-validator - -#include -#include -#include -#include - -#define GET_UTF8(val, GET_BYTE, ERROR)\ - val= (GET_BYTE);\ - {\ - uint32_t top = (val & 128) >> 1;\ - if ((val & 0xc0) == 0x80 || val >= 0xFE)\ - {ERROR}\ - while (val & top) {\ - unsigned int tmp = (GET_BYTE) - 128;\ - if(tmp>>6)\ - {ERROR}\ - val= (val<<6) + tmp;\ - top <<= 5;\ - }\ - val &= (top << 1) - 1;\ - } - -typedef enum _cpuid_register -{ - eax = 0, - ebx = 1, - ecx = 2, - edx = 3 -}cpuid_register; - -static inline bool -has_cpuid_bits(unsigned int level, cpuid_register reg, unsigned int bits) -{ - // Check that the level in question is supported. - int regs[4]; - __cpuid(regs, level & 0x80000000u); - if ((unsigned)(regs[0]) < level) - { - return false; - } - // "The __cpuid intrinsic clears the ECX register before calling the cpuid - // instruction." - __cpuid(regs, level); - return ((unsigned)(regs[reg]) & bits) == bits; -} - -static inline bool -cpu_has_avx(void) -{ - const unsigned AVX = 1u << 28; - const unsigned OSXSAVE = 1u << 27; - const unsigned XSAVE = 1u << 26; - - const unsigned XMM_STATE = 1u << 1; - const unsigned YMM_STATE = 1u << 2; - const unsigned AVX_STATE = XMM_STATE | YMM_STATE; - - return has_cpuid_bits(1u, ecx, AVX | OSXSAVE | XSAVE) && - // ensure the OS supports XSAVE of YMM registers - (_xgetbv(0) & AVX_STATE) == AVX_STATE; -} - -static inline bool -cpu_has_avx2(void) -{ - return cpu_has_avx() && has_cpuid_bits(7u, ebx, (1u << 5)); -} - -static inline bool -cpu_has_sse4_1(void) -{ - return has_cpuid_bits(1u, ecx, (1u << 19)); -} - -int -z_validate_vec_avx2(__m256i bytes, __m256i shifted_bytes, uint32_t *last_cont) -{ - // Error lookup tables for the first, second, and third nibbles - // Simple macro to make a vector lookup table for use with vpshufb. Since - // AVX2 is two 16-byte halves, we duplicate the input values. -#define V_TABLE_16(...) _mm256_setr_epi8(__VA_ARGS__, __VA_ARGS__) - const __m256i error_1 = V_TABLE_16(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x38); - const __m256i error_2 = V_TABLE_16(0x0B, 0x01, 0x00, 0x00, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x20, 0x20); - const __m256i error_3 = V_TABLE_16(0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2B, 0x33, 0x35, 0x35, 0x31, 0x31, 0x31, 0x31); -#undef V_TABLE_16 - - // Quick skip for ascii-only input. If there are no bytes with the high bit - // set, we don't need to do any more work. We return either valid or - // invalid based on whether we expected any continuation bytes here. - const uint32_t high = _mm256_movemask_epi8(bytes); - if (!high) - { - return *last_cont == 0; - } - - // Which bytes are required to be continuation bytes - uint64_t req = *last_cont; - - // Compute the continuation byte mask by finding bytes that start with - // 11x, 111x, and 1111. For each of these prefixes, we get a bitmask - // and shift it forward by 1, 2, or 3. This loop should be unrolled by - // the compiler, and the (n == 1) branch inside eliminated. - uint32_t set = high; - set &= _mm256_movemask_epi8(_mm256_slli_epi16(bytes, 1)); - // A bitmask of the actual continuation bytes in the input - // Mark continuation bytes: those that have the high bit set but - // not the next one - const uint32_t cont = high ^ set; - - // We add the shifted mask here instead of ORing it, which would - // be the more natural operation, so that this line can be done - // with one lea. While adding could give a different result due - // to carries, this will only happen for invalid UTF-8 sequences, - // and in a way that won't cause it to pass validation. Reasoning: - // Any bits for required continuation bytes come after the bits - // for their leader bytes, and are all contiguous. For a carry to - // happen, two of these bit sequences would have to overlap. If - // this is the case, there is a leader byte before the second set - // of required continuation bytes (and thus before the bit that - // will be cleared by a carry). This leader byte will not be - // in the continuation mask, despite being required. QEDish. - req += (uint64_t) set << 1; - set &= _mm256_movemask_epi8(_mm256_slli_epi16(bytes, 2)); - req += (uint64_t) set << 2; - set &= _mm256_movemask_epi8(_mm256_slli_epi16(bytes, 3)); - req += (uint64_t) set << 3; - - // Check that continuation bytes match. We must cast req from uint64_t - // (which holds the carry mask in the upper half) to uint32_t, which - // zeroes out the upper bits - if (cont != (uint32_t) req) - { - return 0; - } - - // Look up error masks for three consecutive nibbles. - const __m256i nibbles = _mm256_set1_epi8(0x0F); - __m256i e_1 = _mm256_shuffle_epi8(error_1, _mm256_and_si256(_mm256_srli_epi16(shifted_bytes, 4), nibbles)); - __m256i e_2 = _mm256_shuffle_epi8(error_2, _mm256_and_si256(shifted_bytes, nibbles)); - __m256i e_3 = _mm256_shuffle_epi8(error_3, _mm256_and_si256(_mm256_srli_epi16(bytes, 4), nibbles)); - - // Check if any bits are set in all three error masks - if (!_mm256_testz_si256(_mm256_and_si256(e_1, e_2), e_3)) - { - return 0; - } - - // Save continuation bits and input bytes for the next round - *last_cont = req >> sizeof(__m256i); - return 1; -} - -static inline int -z_validate_utf8_avx2(const char *data, uint32_t len) -{ - // Keep continuation bits from the previous iteration that carry over to - // each input chunk vector - uint32_t last_cont = 0; - - uint32_t offset = 0; - // Deal with the input up until the last section of bytes - if (len >= sizeof(__m256i)) - { - // We need a vector of the input byte stream shifted forward one byte. - // Since we don't want to read the memory before the data pointer - // (which might not even be mapped), for the first chunk of input just - // use vector instructions. - __m256i shifted_bytes = _mm256_loadu_si256((__m256i *) data); - //__m256i shl_16 = _mm256_permute2x128_si256(shifted_bytes, _mm256_setzero_si256(), 0x03); - // shifted_bytes = _mm256_alignr_epi8(shifted_bytes, shl_16, 15); - shifted_bytes = _mm256_slli_si256(shifted_bytes, 1); - - // Loop over input in sizeof(__m256i)-byte chunks, as long as we can safely read - // that far into memory - for (; offset + sizeof(__m256i) < len; offset += sizeof(__m256i)) - { - __m256i bytes = _mm256_loadu_si256((__m256i *) (data + offset)); - if (!z_validate_vec_avx2(bytes, shifted_bytes, &last_cont)) - { - return 0; - } - shifted_bytes = _mm256_loadu_si256((__m256i *) (data + offset + sizeof(__m256i) - 1)); - } - } - - // Deal with any bytes remaining. Rather than making a separate scalar path, - // just fill in a buffer, reading bytes only up to len, and load from that. - if (offset < len) - { - uint8_t buffer[2 * sizeof(__m256i)] = { 0 }; - - if (offset != 0) - { - buffer[0] = data[offset - 1]; - } - __movsb(buffer + 1, (const uint8_t *) (data + offset), len - offset); - - __m256i shifted_bytes = _mm256_load_si256((__m256i *) buffer); - __m256i bytes = _mm256_loadu_si256((__m256i *) (buffer + 1)); - if (!z_validate_vec_avx2(bytes, shifted_bytes, &last_cont)) - { - return 0; - } - } - - // The input is valid if we don't have any more expected continuation bytes - return last_cont == 0; -} - -static int -z_validate_vec_sse4(__m128i bytes, __m128i shifted_bytes, uint32_t *last_cont) -{ - // Error lookup tables for the first, second, and third nibbles - const __m128i error_1 = _mm_setr_epi8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x38); - const __m128i error_2 = _mm_setr_epi8(0x0B, 0x01, 0x00, 0x00, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x20, 0x20); - const __m128i error_3 = _mm_setr_epi8(0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2B, 0x33, 0x35, 0x35, 0x31, 0x31, 0x31, 0x31); - - // Quick skip for ascii-only input. If there are no bytes with the high bit - // set, we don't need to do any more work. We return either valid or - // invalid based on whether we expected any continuation bytes here. - const uint32_t high = _mm_movemask_epi8(bytes); - if (!high) - { - return *last_cont == 0; - } - - // Which bytes are required to be continuation bytes - uint32_t req = *last_cont; - - // Compute the continuation byte mask by finding bytes that start with - // 11x, 111x, and 1111. For each of these prefixes, we get a bitmask - // and shift it forward by 1, 2, or 3. This loop should be unrolled by - // the compiler, and the (n == 1) branch inside eliminated. - uint32_t set = high; - set &= _mm_movemask_epi8(_mm_slli_epi16(bytes, 1)); - // A bitmask of the actual continuation bytes in the input - // Mark continuation bytes: those that have the high bit set but - // not the next one - const uint32_t cont = high ^ set; - // We add the shifted mask here instead of ORing it, which would - // be the more natural operation, so that this line can be done - // with one lea. While adding could give a different result due - // to carries, this will only happen for invalid UTF-8 sequences, - // and in a way that won't cause it to pass validation. Reasoning: - // Any bits for required continuation bytes come after the bits - // for their leader bytes, and are all contiguous. For a carry to - // happen, two of these bit sequences would have to overlap. If - // this is the case, there is a leader byte before the second set - // of required continuation bytes (and thus before the bit that - // will be cleared by a carry). This leader byte will not be - // in the continuation mask, despite being required. QEDish. - req += set << 1; - set &= _mm_movemask_epi8(_mm_slli_epi16(bytes, 2)); - req += set << 2; - set &= _mm_movemask_epi8(_mm_slli_epi16(bytes, 3)); - req += set << 3; - - // Check that continuation bytes match. We must cast req from uint32_t - // (which holds the carry mask in the upper half) to uint16_t, which - // zeroes out the upper bits - if (cont != (uint16_t) req) - { - return 0; - } - - // Look up error masks for three consecutive nibbles. - const __m128i nibbles = _mm_set1_epi8(0x0F); - __m128i e_1 = _mm_shuffle_epi8(error_1, _mm_and_si128(_mm_srli_epi16(shifted_bytes, 4), nibbles)); - __m128i e_2 = _mm_shuffle_epi8(error_2, _mm_and_si128(shifted_bytes, nibbles)); - __m128i e_3 = _mm_shuffle_epi8(error_3, _mm_and_si128(_mm_srli_epi16(bytes, 4), nibbles)); - - // Check if any bits are set in all three error masks - if (!_mm_test_all_zeros(_mm_and_si128(e_1, e_2), e_3)) - { - return 0; - } - - // Save continuation bits and input bytes for the next round - *last_cont = req >> sizeof(__m128i); - return 1; -} - -static inline bool -z_validate_utf8_sse4(const char *data, uint32_t len) -{ - // Keep continuation bits from the previous iteration that carry over to - // each input chunk vector - uint32_t last_cont = 0; - - uint32_t offset = 0; - // Deal with the input up until the last section of bytes - if (len >= sizeof(__m128i)) - { - // We need a vector of the input byte stream shifted forward one byte. - // Since we don't want to read the memory before the data pointer - // (which might not even be mapped), for the first chunk of input just - // use vector instructions. - __m128i shifted_bytes = _mm_loadu_si128((__m128i *) data); - // shifted_bytes = _mm_alignr_epi8(shifted_bytes, _mm_setzero_si128(), 15); - shifted_bytes = _mm_slli_si128(shifted_bytes, 1); - - // Loop over input in sizeof(__m128i)-byte chunks, as long as we can safely read - // that far into memory - for (; offset + sizeof(__m128i) < len; offset += sizeof(__m128i)) - { - __m128i bytes = _mm_loadu_si128((__m128i *) (data + offset)); - if (!z_validate_vec_sse4(bytes, shifted_bytes, &last_cont)) - { - return 0; - } - shifted_bytes = _mm_loadu_si128((__m128i *) (data + offset + sizeof(__m128i) - 1)); - } - } - - // Deal with any bytes remaining. Rather than making a separate scalar path, - // just fill in a buffer, reading bytes only up to len, and load from that. - if (offset < len) - { - uint8_t buffer[2 * sizeof(__m128i)] = { 0 }; - - if (offset != 0) - { - buffer[0] = data[offset - 1]; - } - __movsb(buffer + 1, (const uint8_t *) (data + offset), len - offset); - - __m128i shifted_bytes = _mm_load_si128((__m128i *) (buffer)); - __m128i bytes = _mm_loadu_si128((__m128i *) (buffer + 1)); - if (!z_validate_vec_sse4(bytes, shifted_bytes, &last_cont)) - { - return 0; - } - } - - // The input is valid if we don't have any more expected continuation bytes - return last_cont == 0; -} - -static bool -check_utf8(const uint8_t *str) -{ - const uint8_t *byte; - uint32_t codepoint, min; - while (*str) - { - byte = str; - if ((*str >> 7) == 0) - { - ++str; - continue; - } - GET_UTF8(codepoint, *(byte++), return false;); - min = byte - str == 1 ? 0 : byte - str == 2 ? 0x80 : 1 << (5 * (byte - str) - 4); - if (codepoint < min || codepoint >= 0x110000 || (codepoint >= 0xD800 && codepoint <= 0xDFFF)) - { - return false; - } - str = byte; - } - return true; -} - -bool -on_encoding_validate_utf8(const char *data, size_t len) -{ - if (cpu_has_avx2()) - { - return z_validate_utf8_avx2(data, (uint32_t) len); - } - else if (cpu_has_sse4_1()) - { - return z_validate_utf8_sse4(data, (uint32_t) len); - } - else - { - return check_utf8((const uint8_t *) data); - } -} diff --git a/src/eu_encoding_utf8.h b/src/eu_encoding_utf8.h deleted file mode 100644 index 6c3cf67c..00000000 --- a/src/eu_encoding_utf8.h +++ /dev/null @@ -1,32 +0,0 @@ -/****************************************************************************** - * This file is part of Skylark project - * Copyright ©2023 Hua andy - - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ - -#ifndef _H_SKYLARK_ENCODING_UTF8_ -#define _H_SKYLARK_ENCODING_UTF8_ - -#ifdef __cplusplus -extern "C" { -#endif - -bool on_encoding_validate_utf8(const char *data, size_t len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/eu_file.c b/src/eu_file.c index a683b4e6..ee5b67b4 100644 --- a/src/eu_file.c +++ b/src/eu_file.c @@ -250,13 +250,54 @@ on_file_push_recent(const eu_tabpage *pnode) if (pnode && util_make_u8(pnode->pathfile, precent->path, MAX_BUFFER)[0]) { // 也支持16进制编辑器获取实时位置 precent->postion = eu_sci_call((eu_tabpage *)pnode, SCI_GETCURRENTPOS, 0, 0); - precent->hex = !(pnode->pmod && pnode->plugin) ? pnode->hex_mode : 0; + precent->hex = pnode->hex_mode; on_sql_file_recent_thread(precent); } free(precent); } } +static file_backup * +on_file_get_bakup(const eu_tabpage *pnode) +{ + file_backup *pbak = (file_backup *)calloc(1, sizeof(file_backup)); + if (pnode && pbak) + { + pbak->x = -1, pbak->y = -1; + pbak->postion = eu_sci_call((eu_tabpage *)pnode, SCI_GETCURRENTPOS, 0, 0); + pbak->tab_id = on_tabpage_get_index(pnode); + pbak->cp = pnode->codepage; + pbak->bakcp = pnode->bakcp; + pbak->eol = pnode->eol; + pbak->blank = pnode->is_blank; + pbak->hex = pnode->hex_mode; + pbak->focus = pnode->last_focus; + pbak->zoom = pnode->zoom_level != SELECTION_ZOOM_LEVEEL ? pnode->zoom_level : 0; + pbak->status = pnode->be_modify ? 1 : 0; + pbak->view = pnode->view; + _tcscpy(pbak->rel_path, pnode->pathfile); + _tcscpy(pbak->bak_path, pbak->status ? pnode->bakpath : _T("")); + if (!TAB_HEX_MODE(pnode) && !TAB_HAS_PDF(pnode)) + { + on_search_page_mark((eu_tabpage *)pnode, pbak->mark_id, MAX_BUFFER-1); + on_search_fold_kept((eu_tabpage *)pnode, pbak->fold_id, MAX_BUFFER-1); + } + } + return pbak; +} + +void +on_file_filedb_update(const eu_tabpage *pnode) +{ + file_backup *pbak = NULL; + const bool doing = eu_get_config() && eu_get_config()->m_session && eu_get_config()->m_up_notify > 0; + if (doing && pnode && (pbak = (on_file_get_bakup(pnode)))) + { + eu_update_backup_table(pbak, DB_FILE); + free(pbak); + } +} + void on_file_clear_recent(void) { @@ -412,63 +453,62 @@ on_file_splite_path(const TCHAR *full_path, TCHAR *pathname, TCHAR *filename, TC } int -on_file_new(void) +on_file_new(eu_tabpage *psrc) { - eu_tabpage *pnode = NULL; + eu_tabpage *pnode = psrc; TCHAR filename[100] = {0}; const uint8_t *bom_str = NULL; - if ((pnode = (eu_tabpage *) calloc(1, sizeof(eu_tabpage))) == NULL) - { - return EUE_POINT_NULL; - } - else + if (pnode || (pnode = (eu_tabpage *) calloc(1, sizeof(eu_tabpage)))) { pnode->is_blank = true; + pnode->be_modify = false; + pnode->fn_modify = false; pnode->begin_pos = -1; pnode->tab_id = -1; + if (on_tabpage_generator(filename, 100)[0]) + { + _tcscpy(pnode->pathfile, filename); + _tcscpy(pnode->filename, filename); + } + if (on_tabpage_add(pnode)) + { + eu_safe_free(pnode); + return EUE_INSERT_TAB_FAIL; + } + else + { + on_sci_before_file(pnode, true); + eu_sci_call(pnode, SCI_CLEARALL, 0, 0); + pnode->eol = eu_get_config()->new_file_eol; + pnode->codepage = eu_get_config()->new_file_enc; + } + switch (pnode->codepage) + { + case IDM_UNI_UTF8B: + bom_str = (const uint8_t *) "\xEF\xBB\xBF"; + break; + case IDM_UNI_UTF16LEB: + bom_str = (const uint8_t *) "\xFF\xFE"; + break; + case IDM_UNI_UTF16BEB: + bom_str = (const uint8_t *) "\xFE\xFF"; + break; + default: + break; + } + if (bom_str) + { + on_encoding_set_bom(bom_str, pnode); + } + if (true) + { + on_file_update_time(pnode, time(NULL)); + on_sci_after_file(pnode, true); + on_tabpage_selection(pnode, -1); + } + return SKYLARK_OK; } - if (on_tabpage_generator(filename, 100)[0]) - { - _tcscpy(pnode->pathfile, filename); - _tcscpy(pnode->filename, filename); - } - if (on_tabpage_add(pnode)) - { - eu_safe_free(pnode); - return EUE_INSERT_TAB_FAIL; - } - else - { - on_sci_before_file(pnode, true); - eu_sci_call(pnode, SCI_CLEARALL, 0, 0); - pnode->eol = eu_get_config()->new_file_eol; - pnode->codepage = eu_get_config()->new_file_enc; - } - switch (pnode->codepage) - { - case IDM_UNI_UTF8B: - bom_str = (const uint8_t *) "\xEF\xBB\xBF"; - break; - case IDM_UNI_UTF16LEB: - bom_str = (const uint8_t *) "\xFF\xFE"; - break; - case IDM_UNI_UTF16BEB: - bom_str = (const uint8_t *) "\xFE\xFF"; - break; - default: - break; - } - if (bom_str) - { - on_encoding_set_bom(bom_str, pnode); - } - if (true) - { - on_file_update_time(pnode, time(NULL)); - on_sci_after_file(pnode, true); - on_tabpage_selection(pnode, -1); - } - return SKYLARK_OK; + return EUE_POINT_NULL; } uint64_t @@ -480,8 +520,8 @@ on_file_get_avail_phys(void) return (statex.ullAvailPhys); } -static bool -on_file_map_hex(eu_tabpage *pnode, HANDLE hfile, size_t nbyte) +bool +on_file_map_hex(eu_tabpage *pnode, HANDLE hfile, const size_t nbyte) { if (!pnode || pnode->phex) { @@ -518,14 +558,13 @@ on_file_map_hex(eu_tabpage *pnode, HANDLE hfile, size_t nbyte) static int on_file_set_codepage(eu_tabpage *pnode, const HANDLE hfile, const TCHAR *pfull) { - int check_len = 0; int bytesread = 0; int err = SKYLARK_OK; uint8_t *buf = NULL; - check_len = eu_int_cast(pnode->raw_size > BUFF_SIZE ? BUFF_SIZE : pnode->raw_size); + const int check_len = (const int)(pnode->raw_size > BUFF_8M ? BUFF_8M : pnode->raw_size); do { - if (!(buf = (uint8_t *)calloc(1, check_len+1))) + if (!(buf = (uint8_t *)malloc(check_len+1))) { err = EUE_NOT_ENOUGH_MEMORY; break; @@ -544,12 +583,13 @@ on_file_set_codepage(eu_tabpage *pnode, const HANDLE hfile, const TCHAR *pfull) } else // 如果是utf8编码, 获取换行符, 否则, 等编码转换后再获取换行符 { + buf[bytesread] = '\0'; pnode->codepage = eu_try_encoding(buf, bytesread, false, pfull); if (pnode->codepage < IDM_UNI_UTF16LE) { pnode->eol = on_encoding_line_mode((const char *)buf, bytesread); } - if (pnode->codepage != IDM_OTHER_BIN) + if (pnode->codepage < IDM_OTHER_BIN) { on_encoding_set_bom((const uint8_t *) buf, pnode); } @@ -666,9 +706,9 @@ on_file_preload(eu_tabpage *pnode, file_backup *pbak) { return EUE_PATH_NULL; } - if (pbak->hex) + else { - pnode->hex_mode = true; + pnode->hex_mode = pbak->hex; } if (url_has_remote(pfull)) { @@ -697,39 +737,40 @@ on_file_preload(eu_tabpage *pnode, file_backup *pbak) pnode->eol = pbak->eol; pnode->nc_pos = pbak->postion; pnode->codepage = pbak->cp; + // 如果是二进制文件, 以on_file_map_hex打开 if (!TAB_NOT_BIN(pnode)) { - pnode->hex_mode = true; if (!on_file_map_hex(pnode, hfile, 0)) { err = EUE_MAP_HEX_ERR; } + else + { + pnode->hex_mode = TYPES_HEX; + } goto pre_clean; } } - if (pnode->hex_mode) - { + if (TAB_HEX_MODE(pnode)) + { // 如果是16进制模式, 文本以及插件也可能处于16进制模式 if ((err = !on_file_map_hex(pnode, hfile, 0)) != 0) { + err = EUE_MAP_HEX_ERR; goto pre_clean; } - if (pbak->cp && (pbak->bakcp == pbak->cp || !pbak->status)) + if (pbak->cp) { pnode->phex->hex_ascii = true; - } - else if (pbak->cp) - { on_encoding_set_bom_from_cp(pnode); } else { - pnode->phex->hex_ascii = true; err = on_file_set_codepage(pnode, hfile, pfull); } goto pre_clean; } if (pnode->pmod) - { + { // 如果加载了插件, 后续on_file_load再次检查 err = SKYLARK_OK; goto pre_clean; } @@ -740,18 +781,21 @@ on_file_preload(eu_tabpage *pnode, file_backup *pbak) } if ((err = on_file_set_codepage(pnode, hfile, pfull)) == SKYLARK_OK && !TAB_NOT_BIN(pnode)) { // 不在备份中打开, 测试是否16进制文件? - pnode->hex_mode = true; if (!on_file_map_hex(pnode, hfile, 0)) { err = EUE_MAP_HEX_ERR; } + else + { + pnode->hex_mode = TYPES_HEX; + } } pre_clean: share_close(hfile); return err; } -static int +int on_file_load_plugins(eu_tabpage *pnode, bool route_open) { int ret = np_plugins_initialize(pnode->pmod, &pnode->plugin); @@ -761,6 +805,8 @@ on_file_load_plugins(eu_tabpage *pnode, bool route_open) ret = pnode->plugin->funcs.newp(&pnode->plugin->npp, NULL); if (ret == 0) { + pnode->hex_mode = TYPES_PLUGIN; + pnode->codepage = IDM_OTHER_PLUGIN; pnode->plugin->win.window = pnode->hwnd_sc; pnode->plugin->funcs.setwindow(&pnode->plugin->npp, &pnode->plugin->win); if (!route_open) @@ -770,17 +816,13 @@ on_file_load_plugins(eu_tabpage *pnode, bool route_open) pnode->plugin->stream.url = (const char *)u8_file; pnode->plugin->stream.end = (intptr_t)pnode->raw_size; ret = pnode->plugin->funcs.asfile(&pnode->plugin->npp, &pnode->plugin->stream); - if (!ret) - { - pnode->hex_mode = true; - } } else { uint16_t type; pnode->plugin->stream.end = (intptr_t)pnode->raw_size; ret = pnode->plugin->funcs.newstream(&pnode->plugin->npp, &pnode->plugin->stream, false, &type); - if (!ret) + if (ret == NP_NO_ERROR) { pnode->plugin->funcs.writeready(&pnode->plugin->npp, &pnode->plugin->stream); } @@ -812,12 +854,14 @@ on_file_load(eu_tabpage *pnode, file_backup *pbak, const bool force) { pfull = pnode->pathfile; } - if (pnode->hex_mode || (pnode->is_blank && !is_utf8)) - { + if (TAB_HEX_MODE(pnode) || (pnode->is_blank && !is_utf8)) + { // 16进制模式下, on_file_preload已经打开 + // 新建的空白文件, 不用载入数据 return SKYLARK_OK; } if (pnode->pmod) { + eu_logmsg("%s: on_file_load_plugins execute\n", __FUNCTION__); return on_file_load_plugins(pnode, false); } if (STR_IS_NUL(pfull)) @@ -926,39 +970,68 @@ on_file_open_if(const TCHAR *pfile, bool selection) } static void -on_file_active_other(int index) +on_file_active_condition(eu_tabpage *pnode, const int index) { - int count = TabCtrl_GetItemCount(g_tabpages); - if (count <= 0) - { // 最后一个标签 - if (!eu_get_config()->m_exit) + if (g_tabpages && eu_get_config()) + { + const int i = index >= 0 ? index : (pnode && pnode->tab_id >= 0 ? pnode->tab_id : 0); + const int count = TabCtrl_GetItemCount(g_tabpages); + if (count < 1) { - file_backup bak = {0}; - share_send_msg(&bak); + if (!eu_get_config()->m_exit) + { + on_file_new(NULL); + } + else if (on_sql_sync_session() == SKYLARK_OK) + { + eu_logmsg("close last tab, skylark exit ...\n"); + SendMessage(eu_module_hwnd(), WM_BACKUP_OVER, 0, 0); + } } - else if (on_sql_sync_session() == SKYLARK_OK) + else if (i >= 0) { - eu_logmsg("close last tab, skylark exit ...\n"); - SendMessage(eu_module_hwnd(), WM_BACKUP_OVER, 0, 0); + switch (eu_get_config()->m_tab_active) + { // 激活另一个标签 + case IDM_VIEW_LEFT_TAB: + on_tabpage_select_index(i > 0 ? i - 1 : count - 1); + break; + case IDM_VIEW_RIGHT_TAB: + on_tabpage_select_index(i > count - 1 ? 0 : i); + break; + case IDM_VIEW_FAR_LEFT_TAB: + on_tabpage_select_index(0); + break; + case IDM_VIEW_FAR_RIGHT_TAB: + on_tabpage_select_index(count - 1); + break; + default: + break; + } } - return; } - switch (eu_get_config()->m_tab_active) - { // 激活另一个标签 - case IDM_VIEW_LEFT_TAB: - on_tabpage_select_index(index > 0 ? index - 1 : count - 1); - break; - case IDM_VIEW_RIGHT_TAB: - on_tabpage_select_index(index > count - 1 ? 0 : index); - break; - case IDM_VIEW_FAR_LEFT_TAB: - on_tabpage_select_index(0); - break; - case IDM_VIEW_FAR_RIGHT_TAB: - on_tabpage_select_index(count - 1); - break; - default: - break; +} + +static void +on_file_active_other(eu_tabpage *pnode) +{ + if (pnode && g_tabpages) + { + const int count = TabCtrl_GetItemCount(g_tabpages); + if (count < 1) + { + if (eu_get_config()->m_exit) + { // 最后一个标签退出设置 + pnode->reason = TABS_MAYBE_EIXT; + } + else if (pnode->reason != TABS_MAYBE_RESERVE) + { + on_file_new(NULL); + } + } + else + { + on_file_active_condition(pnode, -1); + } } } @@ -1033,7 +1106,7 @@ on_file_update_focus(eu_tabpage *pnode, file_backup *pbak) static void on_file_before_open(eu_tabpage *pnode) { - if (!pnode->hex_mode && !pnode->pmod) + if (!TAB_HEX_MODE(pnode) && !pnode->pmod) { on_sci_before_file(pnode, true); eu_sci_call(pnode, SCI_CLEARALL, 0, 0); @@ -1057,7 +1130,7 @@ on_file_after_open(eu_tabpage *pnode, file_backup *pbak) { return SKYLARK_TABCTRL_ERR; } - if (!pnode->hex_mode && !pnode->pmod) + if (!TAB_HEX_MODE(pnode) && !pnode->pmod) { if (strlen(pbak->mark_id) > 0) { // 恢复书签 @@ -1137,7 +1210,7 @@ on_file_node_initialize(eu_tabpage **p, file_backup *pbak) (*p)->eol = -1; (*p)->begin_pos = -1; (*p)->tab_id = -1; - (*p)->hex_mode = !!pbak->hex; + (*p)->hex_mode = pbak->hex; (*p)->is_blank = pbak->blank; (*p)->be_modify = !!pbak->status; if (STR_NOT_NUL(pbak->rel_path)) @@ -1202,11 +1275,11 @@ on_file_only_open(file_backup *pbak, const bool selection) eu_logmsg("we jump to %zd\n", pnode->nc_pos); on_search_jmp_pos(pnode); } - if (!pnode->hex_mode) + if (!TAB_HEX_MODE(pnode)) { - res = pbak && pbak->hex ? hexview_switch_mode(pnode) : res; + res = pbak && pbak->hex == TYPES_HEX ? hexview_switch_mode(pnode) : res; } - else if (pbak && !pbak->hex && !eu_get_config()->m_instance) + else if (pbak && pbak->hex == TYPES_TEXT && !eu_get_config()->m_instance) { res = hexview_switch_mode(pnode); } @@ -1231,6 +1304,7 @@ on_file_only_open(file_backup *pbak, const bool selection) break; } on_file_before_open(pnode); + eu_logmsg("%s: on_file_load execute\n", __FUNCTION__); if (on_file_load(pnode, pbak, false)) { res = EUE_WRITE_TAB_FAIL; @@ -1243,13 +1317,9 @@ on_file_only_open(file_backup *pbak, const bool selection) { if (res == EUE_WRITE_TAB_FAIL) { - int index = on_tabpage_remove(&pnode); - on_file_active_other(index); - } - else - { - on_sci_free_tab(&pnode); + on_file_active_other(on_tabpage_remove(pnode, FILE_SHUTDOWN)); } + on_sci_free_tab(&pnode); } return res; } @@ -1259,7 +1329,7 @@ on_file_open_bakcup(file_backup *pbak) { if (!pbak || (STR_IS_NUL(pbak->rel_path))) { - return on_file_new(); + return on_file_new(NULL); } if (_tcslen(pbak->rel_path) > 0 && pbak->rel_path[_tcslen(pbak->rel_path) - 1] == _T('*')) { @@ -1371,17 +1441,17 @@ on_file_out_open(const int index, uint32_t *pid) sptr_t lineno = eu_sci_call(p, SCI_LINEFROMPOSITION, pos, 0); sptr_t row = eu_sci_call(p, SCI_POSITIONFROMLINE, lineno, 0); _sntprintf(process, MAX_BUFFER, _T("%s%s\"%s\" -n%zd -c%zd"), process, _T(" -noremote "), p->pathfile, lineno+1, pos-row+1); - if (!p->plugin && p->hex_mode) + if (!p->plugin && TAB_HEX_MODE(p)) { _tcsncat(process, _T(" -hex"), MAX_BUFFER); } - err = on_file_close(p, FILE_ONLY_CLOSE); + err = on_file_close(&p, FILE_ONLY_CLOSE); } } else { _sntprintf(process, MAX_BUFFER, _T("%s%s"), process, _T(" -noremote ")); - err = on_file_close(p, FILE_REMOTE_CLOSE); + err = on_file_close(&p, FILE_REMOTE_CLOSE); } if (err == SKYLARK_OK) { @@ -1414,8 +1484,7 @@ on_file_redirect(HWND hwnd, file_backup *pbak) } if (err != SKYLARK_OK && TabCtrl_GetItemCount(g_tabpages) < 1) { // 打开文件失败且标签小于1,则建立一个空白标签页 - err = on_file_new(); - + err = on_file_new(NULL); } return err; } @@ -1443,6 +1512,7 @@ on_file_drop(HDROP hdrop) } } DragFinish(hdrop); + eu_wine_dotool(); return SKYLARK_OK; } @@ -1456,14 +1526,14 @@ on_file_read_remote(void *buffer, size_t size, size_t nmemb, void *stream) len = size * nmemb; if (!pnode->bytes_remaining) { - if (pnode->hex_mode || !pnode->pmod) + if (TAB_HEX_MODE(pnode) || !pnode->pmod) { pnode->codepage = eu_try_encoding(buffer, len, false, pnode->filename); if (pnode->codepage < IDM_UNI_UTF16LE) { pnode->eol = on_encoding_line_mode(buffer, len); } - if (pnode->codepage != IDM_OTHER_BIN) + if (pnode->codepage < IDM_OTHER_BIN) { on_encoding_set_bom((const uint8_t *) buffer, pnode); } @@ -1502,7 +1572,7 @@ on_file_read_remote(void *buffer, size_t size, size_t nmemb, void *stream) } else { - if (pnode->hex_mode || !pnode->pmod) + if (TAB_HEX_MODE(pnode) || !pnode->pmod) { eu_sci_call(pnode, SCI_ADDTEXT, len - offset, (LPARAM)(data + offset)); } @@ -1620,28 +1690,25 @@ on_file_open_remote(remotefs *premote, file_backup *pbak, const bool selection) { if (result == EUE_CURL_NETWORK_ERR) { - int index = on_tabpage_remove(&pnode); - on_file_active_other(index); + on_file_active_other(on_tabpage_remove(pnode, FILE_SHUTDOWN)); MSG_BOX(IDC_MSG_ATTACH_FAIL, IDC_MSG_ERROR, MB_ICONERROR | MB_OK); } - else - { - on_sci_free_tab(&pnode); - } + on_sci_free_tab(&pnode); } else - { - if (!pnode->hex_mode && pnode->pmod && pnode->plugin && pnode->plugin->funcs.write) + { // 远程二进制文件, 选择以插件或16进制编辑器打开 + if (!TAB_HEX_MODE(pnode) && pnode->pmod && pnode->plugin && pnode->plugin->funcs.write) { pnode->raw_size = pnode->bytes_remaining; pnode->plugin->funcs.destroystream(&pnode->plugin->npp, NULL, 0); on_file_update_focus(pnode, NULL); - pnode->hex_mode = true; + pnode->hex_mode = TYPES_PLUGIN; result = on_tabpage_selection(pnode, last_focus); } - else if (!TAB_NOT_BIN(pnode) || pnode->hex_mode) - { - pnode->hex_mode = false; + else if (!TAB_NOT_BIN(pnode) || TAB_HEX_MODE(pnode)) + { // 以下是两个先决条件, 从文件切换到二进制 + pnode->hex_mode = TYPES_TEXT; + pnode->codepage = IDM_OTHER_BIN; result = hexview_switch_mode(pnode); } } @@ -1655,7 +1722,7 @@ on_file_do_write(eu_tabpage *pnode, const TCHAR *pathfilename, const bool isbak, int ret = SKYLARK_OK; bool be_ignore = false; bool be_cache = (bool)isbak; - if (!pnode->hex_mode) + if (!TAB_HEX_MODE(pnode)) { pnode->bytes_remaining = (size_t) eu_sci_call(pnode, SCI_GETLENGTH, 0, 0); be_ignore = pnode->bytes_remaining > BUFF_200M && on_session_thread_id() == GetCurrentThreadId(); @@ -1959,7 +2026,7 @@ on_file_save(eu_tabpage *pnode, const bool save_as) wchar_t msg[PERROR_LEN+1] = {0}; if (TAB_NOT_BIN(pnode)) { - if (pnode->hex_mode) + if (TAB_HEX_MODE(pnode)) { ptext = (char *)hexview_strdup_data(pnode, &buf_len); if (ptext == NULL) @@ -2051,6 +2118,7 @@ on_file_save(eu_tabpage *pnode, const bool save_as) } } on_sci_refresh_ui(pnode); + on_file_filedb_update(pnode); } return err; } @@ -2154,58 +2222,61 @@ on_file_backup_name(eu_tabpage *pnode, wchar_t *pout) return ret; } -static void -on_file_npp_write(eu_tabpage *pnode, const wchar_t *cache_path, bool isbak, int *pstatus) +void +on_file_npp_write(eu_tabpage *pnode, const wchar_t *cache_path, const bool isbak, int *pstatus) { #define TMP_SUFFX (L".$bak~") bool is_cache = isbak && (!eu_get_config()->m_limit || eu_get_config()->m_limit > eu_int_cast(pnode->raw_size/1024/1024)); - if (is_cache) - { - int ret = 0; - bool is_same = false; - wchar_t *tmp_path = NULL; - wchar_t pathfile[MAX_BUFFER] = {0}; - if (!np_plugins_getvalue(&pnode->plugin->funcs, &pnode->plugin->npp, NV_TABTITLE, (void **)&tmp_path) && STR_NOT_NUL(tmp_path)) - { // 未保存之前, 把本地文件先复制到临时文件 - _snwprintf(pathfile, MAX_BUFFER, L"%s", tmp_path); - // 本地文件也可能是之前的备份, 不用复制 - is_same = (STR_NOT_NUL(cache_path) && wcsicmp(pathfile, cache_path) == 0); - if (!is_same) - { - wcsncat(tmp_path, TMP_SUFFX, MAX_BUFFER); - ret = CopyFileW(pathfile, tmp_path, false); + if (pnode && pnode->pmod && pnode->plugin) + { + if (is_cache) + { + int ret = 0; + bool is_same = false; + wchar_t *tmp_path = NULL; + wchar_t pathfile[MAX_BUFFER] = {0}; + if (!np_plugins_getvalue(&pnode->plugin->funcs, &pnode->plugin->npp, NV_TABTITLE, (void **)&tmp_path) && STR_NOT_NUL(tmp_path)) + { // 未保存之前, 把本地文件先复制到临时文件 + _snwprintf(pathfile, MAX_BUFFER, L"%s", tmp_path); + // 本地文件也可能是之前的备份, 不用复制 + is_same = (STR_NOT_NUL(cache_path) && wcsicmp(pathfile, cache_path) == 0); + if (!is_same) + { + wcsncat(tmp_path, TMP_SUFFX, MAX_BUFFER); + ret = CopyFileW(pathfile, tmp_path, false); + } + } + if ((ret || is_same) && STR_NOT_NUL(tmp_path)) + { // 保存本地文件 + np_plugins_savefile(&pnode->plugin->funcs, &pnode->plugin->npp); + if (!is_same) + { // 并移动到cache_path + ret = MoveFileW(pathfile, cache_path); + // 本地文件恢复未修改之前的状态 + ret = MoveFileExW(tmp_path, pathfile, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED); + } } + eu_safe_free(tmp_path); } - if ((ret || is_same) && STR_NOT_NUL(tmp_path)) - { // 保存本地文件 + else if (!url_has_remote(pnode->pathfile)) + { // no cache, 则自动保存 np_plugins_savefile(&pnode->plugin->funcs, &pnode->plugin->npp); - if (!is_same) - { // 并移动到cache_path - ret = MoveFileW(pathfile, cache_path); - // 本地文件恢复未修改之前的状态 - ret = MoveFileExW(tmp_path, pathfile, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED); + if (pstatus) + { + *pstatus = 0; } } - eu_safe_free(tmp_path); - } - else if (!url_has_remote(pnode->pathfile)) - { // no cache, 则自动保存 - np_plugins_savefile(&pnode->plugin->funcs, &pnode->plugin->npp); - if (pstatus) - { - *pstatus = 0; + else + { // 网络流文件的修改丢弃 + on_sql_delete_backup_row(pnode); } } - else - { // 网络流文件的修改丢弃 - on_sql_delete_backup_row(pnode); - } #undef TMP_SUFFX } static bool on_file_cache_protect(eu_tabpage *pnode) -{ +{ // 非cache目录内文件 if (pnode && pnode->pathfile[0]) { TCHAR cache[MAX_BUFFER] = {0}; @@ -2215,6 +2286,24 @@ on_file_cache_protect(eu_tabpage *pnode) return false; } +bool +on_file_get_bakpath(eu_tabpage *pnode) +{ + TCHAR buf[QW_SIZE] = {0}; + if (pnode) + { + if (!on_file_backup_name(pnode, buf)) + { + on_file_guid(buf, QW_SIZE - 1); + } + } + if (buf[0]) + { + _sntprintf(pnode->bakpath, MAX_BUFFER, _T("%s\\cache\\%s"), eu_config_path, buf); + } + return (buf[0] != 0); +} + static void on_file_save_backup(eu_tabpage *pnode, const CLOSE_MODE mode) { @@ -2222,9 +2311,10 @@ on_file_save_backup(eu_tabpage *pnode, const CLOSE_MODE mode) { if (!pnode->is_blank || TAB_NOT_NUL(pnode)) { + const bool autobak = TAB_NOT_BIN(pnode) && !TAB_HAS_PDF(pnode); file_backup filebak = {0}; filebak.cp = pnode->codepage; - filebak.bakcp = !TAB_NOT_BIN(pnode) ? IDM_OTHER_BIN : IDM_UNI_UTF8; + filebak.bakcp = pnode->bakcp; if (pnode->be_modify) { TCHAR buf[QW_SIZE] = {0}; @@ -2237,40 +2327,48 @@ on_file_save_backup(eu_tabpage *pnode, const CLOSE_MODE mode) { eu_logmsg("%s: error, buf is null\n", __FUNCTION__); } - else if (util_isxdigit_string(buf, eu_int_cast(_tcslen(buf) - 2))) + else { - size_t buf_len = _tcslen(buf); - if (buf_len > 2 && buf[buf_len - 1] == _T('~') && buf[buf_len - 2] == _T('~')) + if (util_isxdigit_string(buf, eu_int_cast(_tcslen(buf) - 2))) { - eu_logmsg("%s: File name may be incorrect\n", __FUNCTION__); - buf[buf_len - 2] = 0; + size_t buf_len = _tcslen(buf); + if (buf_len > 2 && buf[buf_len - 1] == _T('~') && buf[buf_len - 2] == _T('~')) + { + eu_logmsg("%s: File name may be incorrect\n", __FUNCTION__); + buf[buf_len - 2] = 0; + } } + _sntprintf(filebak.bak_path, MAX_BUFFER, _T("%s\\cache\\%s"), eu_config_path, buf); } - if (!pnode->pmod) + if (mode == FILE_AUTO_SAVE) { - _sntprintf(filebak.bak_path, MAX_BUFFER, _T("%s\\cache\\%s"), eu_config_path, buf); - on_file_do_write(pnode, filebak.bak_path, true, false, &filebak.status); + if (autobak) + { + on_file_do_write(pnode, filebak.bak_path, true, false, &filebak.status); + } } - else + else if (TAB_HAS_PDF(pnode) && !TAB_HEX_MODE(pnode)) { - _sntprintf(filebak.bak_path, MAX_BUFFER, _T("%s\\cache\\%s"), eu_config_path, buf); on_file_npp_write(pnode, filebak.bak_path, true, &filebak.status); } - if (pnode->hex_mode && pnode->phex && pnode->phex->hex_ascii) + else { - filebak.bakcp = pnode->codepage; + on_file_do_write(pnode, filebak.bak_path, true, false, &filebak.status); } } - _tcscpy(filebak.rel_path, pnode->pathfile); - filebak.tab_id = pnode->tab_id; - filebak.eol = pnode->eol; - filebak.blank = pnode->is_blank; - filebak.hex = !(pnode->pmod && pnode->plugin) ? pnode->hex_mode : 0; - filebak.focus = pnode->last_focus; - filebak.zoom = pnode->zoom_level != SELECTION_ZOOM_LEVEEL ? pnode->zoom_level : 0; - on_search_page_mark(pnode, filebak.mark_id, MAX_BUFFER-1); - on_search_fold_kept(pnode, filebak.fold_id, MAX_BUFFER-1); - filebak.postion = eu_sci_call(pnode, SCI_GETCURRENTPOS, 0, 0); + if (true) + { + _tcscpy(filebak.rel_path, pnode->pathfile); + filebak.tab_id = pnode->tab_id; + filebak.eol = pnode->eol; + filebak.blank = pnode->is_blank; + filebak.hex = pnode->hex_mode; + filebak.focus = pnode->last_focus; + filebak.zoom = pnode->zoom_level != SELECTION_ZOOM_LEVEEL ? pnode->zoom_level : 0; + on_search_page_mark(pnode, filebak.mark_id, MAX_BUFFER-1); + on_search_fold_kept(pnode, filebak.fold_id, MAX_BUFFER-1); + filebak.postion = eu_sci_call(pnode, SCI_GETCURRENTPOS, 0, 0); + } if (mode == FILE_REMOTE_CLOSE) { filebak.sync = (int)(url_has_remote(filebak.rel_path) ? 1 : @@ -2287,14 +2385,24 @@ on_file_save_backup(eu_tabpage *pnode, const CLOSE_MODE mode) } if (eu_exist_file(filebak.bak_path)) { - TCHAR tmp[MAX_BUFFER] = {0}; - _sntprintf(tmp, MAX_BUFFER, _T("%s~~"), filebak.bak_path); - util_copy_file(filebak.bak_path, tmp, false); - if (!_InterlockedCompareExchange(&pnode->lock_id, 1, 0)) + if (autobak) { - _tcsncat(filebak.bak_path, _T("~~"), MAX_BUFFER); - eu_update_backup_table(&filebak, DB_FILE); - filebak.bak_path[_tcslen(filebak.bak_path) - 2] = 0; + TCHAR tmp[MAX_BUFFER] = {0}; + _sntprintf(tmp, MAX_BUFFER, _T("%s~~"), filebak.bak_path); + util_copy_file(filebak.bak_path, tmp, false); + } + if (!_InterlockedCompareExchange(&pnode->lock_id, 1, 0)) + { // 写入文件数据库, 仅写入一次 + if (autobak) + { + _tcsncat(filebak.bak_path, _T("~~"), MAX_BUFFER); + eu_update_backup_table(&filebak, DB_FILE); + filebak.bak_path[_tcslen(filebak.bak_path) - 2] = 0; + } + else + { + eu_update_backup_table(&filebak, DB_FILE); + } } } eu_update_backup_table(&filebak, DB_MEM); @@ -2320,7 +2428,7 @@ on_file_auto_backup(void) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && p->be_modify && !p->hex_mode && !p->pmod && !on_file_cache_protect(p)) + if (p && p->be_modify && !on_file_cache_protect(p)) { if (need_lock) { @@ -2336,14 +2444,13 @@ on_file_auto_backup(void) } int -on_file_close(eu_tabpage *pnode, CLOSE_MODE mode) +on_file_close(eu_tabpage **ppnode, const CLOSE_MODE mode) { EU_VERIFY(g_tabpages != NULL); - int index = -1; int err = SKYLARK_OK; int ifocus = TabCtrl_GetCurSel(g_tabpages); eu_tabpage *p = on_tabpage_get_ptr(ifocus); - if (!pnode) + if (STR_IS_NUL(ppnode)) { return EUE_TAB_NULL; } @@ -2351,10 +2458,10 @@ on_file_close(eu_tabpage *pnode, CLOSE_MODE mode) { // do nothing } - else if (on_sci_doc_modified(pnode)) + else if (on_sci_doc_modified(*ppnode)) { TCHAR msg[100 + MAX_BUFFER]; - if (pnode->pathfile[0] == 0) + if ((*ppnode)->pathfile[0] == 0) { LOAD_I18N_RESSTR(IDC_MSG_SAVE_STR1, save_str); _sntprintf(msg, _countof(msg) - 1, save_str); @@ -2362,11 +2469,11 @@ on_file_close(eu_tabpage *pnode, CLOSE_MODE mode) else { LOAD_I18N_RESSTR(IDC_MSG_SAVE_STR2, save_str); - _sntprintf(msg, _countof(msg) - 1, save_str, pnode->pathfile); + _sntprintf(msg, _countof(msg) - 1, save_str, (*ppnode)->pathfile); } LOAD_APP_RESSTR(IDS_APP_TITLE, title); /* 如果需要确认, 选中该标签 */ - on_tabpage_selection(pnode, -1); + on_tabpage_selection((*ppnode), -1); int decision = eu_msgbox(eu_module_hwnd(), msg, title, MB_YESNOCANCEL); if (decision == IDCANCEL) { @@ -2375,41 +2482,45 @@ on_file_close(eu_tabpage *pnode, CLOSE_MODE mode) } else if (decision == IDYES) { - err = on_file_save(pnode, false); + err = on_file_save((*ppnode), false); } else { - pnode->be_modify = false; + (*ppnode)->be_modify = false; } } if (!err) { if (eu_get_config()->m_session) { - on_file_save_backup(pnode, mode); + on_file_save_backup((*ppnode), mode); } else { - on_sql_delete_backup_row(pnode); + on_sql_delete_backup_row((*ppnode)); } /* 清理该文件的位置导航信息 */ - on_search_clean_navigate_this(pnode); + on_search_clean_navigate_this((*ppnode)); /* 排序最近关闭文件的列表 */ - if (file_click_close(mode) && !pnode->is_blank) + if (file_click_close(mode) && !(*ppnode)->is_blank) { - on_file_push_recent(pnode); + on_file_push_recent((*ppnode)); } /* 关闭标签后需要激活其他标签 */ - if ((index = on_tabpage_remove(&pnode)) >= 0 && (mode == FILE_REMOTE_CLOSE || mode == FILE_ONLY_CLOSE)) + if (on_tabpage_remove((*ppnode), mode)) { - if (index == ifocus || mode == FILE_REMOTE_CLOSE) - { - on_file_active_other(index); - } - else if (p) + if (mode == FILE_REMOTE_CLOSE || mode == FILE_ONLY_CLOSE) { - on_tabpage_selection(p, -1); + if ((*ppnode)->tab_id == ifocus || mode == FILE_REMOTE_CLOSE) + { + on_file_active_other((*ppnode)); + } + else if (p) + { + on_tabpage_selection(p, -1); + } } + on_sci_free_tab(ppnode); } } return err; @@ -2423,7 +2534,7 @@ on_file_all_close(void) for (int index = 0; index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(this_index); - if (p && on_file_close(p, FILE_ALL_CLOSE)) + if (p && on_file_close(&p, FILE_ALL_CLOSE)) { ++this_index; } @@ -2452,13 +2563,13 @@ on_file_left_close(void) { int first = 0; int this_index = TabCtrl_GetCurSel(g_tabpages); + eu_tabpage *p = NULL; eu_tabpage *pnode = on_tabpage_get_ptr(this_index); for (int index = 0; index < this_index; ++index) { - eu_tabpage *p = on_tabpage_get_ptr(first); - if (p) + if ((p = on_tabpage_get_ptr(first))) { - if (on_file_close(p, FILE_EXCLUDE_CLOSE)) + if (on_file_close(&p, FILE_EXCLUDE_CLOSE)) { ++first; } @@ -2474,12 +2585,12 @@ on_file_right_close(void) int count = TabCtrl_GetItemCount(g_tabpages); const int this_index = TabCtrl_GetCurSel(g_tabpages); int right = count - 1; + eu_tabpage *p = NULL; for (; this_index < right; --right) { - eu_tabpage *p = on_tabpage_get_ptr(right); - if (p) + if ((p = on_tabpage_get_ptr(right))) { - if (on_file_close(p, FILE_EXCLUDE_CLOSE)) + if (on_file_close(&p, FILE_EXCLUDE_CLOSE)) { continue; } @@ -2507,7 +2618,7 @@ on_file_exclude_close(eu_tabpage *pnode) ++this_index; continue; } - if ((p = on_tabpage_get_ptr(this_index)) && on_file_close(p, FILE_EXCLUDE_CLOSE)) + if ((p = on_tabpage_get_ptr(this_index)) && on_file_close(&p, FILE_EXCLUDE_CLOSE)) { ++this_index; } @@ -2518,21 +2629,43 @@ on_file_exclude_close(eu_tabpage *pnode) return SKYLARK_OK; } +int +on_file_unchange_close(eu_tabpage *pnode) +{ + if (pnode && g_tabpages) + { + int this_index = TabCtrl_GetCurSel(g_tabpages); + const int count = TabCtrl_GetItemCount(g_tabpages); + for (int index = count - 1; index >= 0; --index) + { + if ((pnode = on_tabpage_get_ptr(index)) && !pnode->be_modify) + { + on_file_close(&pnode, FILE_EXCLUDE_CLOSE); + if (index < this_index) + { + --this_index; + } + } + } + on_file_active_condition(pnode, this_index); + } + return SKYLARK_OK; +} + static unsigned __stdcall on_file_check_save(void *lp) { int err = 0; int at_focus = -1; - int count = TabCtrl_GetItemCount(g_tabpages); + eu_tabpage *pnode = NULL; on_proc_sync_wait(); if (eu_get_config()->m_session) { at_focus = TabCtrl_GetCurSel(g_tabpages); } - for (int index = 0; index < count; ++index) + for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { - eu_tabpage *pnode = on_tabpage_get_ptr(err); - if (pnode) + if ((pnode = on_tabpage_get_ptr(err))) { pnode->tab_id = index; pnode->zoom_level = pnode->zoom_level != SELECTION_ZOOM_LEVEEL ? (int) eu_sci_call(pnode, SCI_GETZOOM, 0, 0) : 0; @@ -2540,7 +2673,7 @@ on_file_check_save(void *lp) { pnode->last_focus = pnode->tab_id == at_focus; } - if (on_file_close(pnode, FILE_SHUTDOWN)) + if (on_file_close(&pnode, FILE_SHUTDOWN)) { ++err; continue; @@ -2726,7 +2859,7 @@ on_file_restore_recent(void) void on_file_reload_current(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !url_has_remote(pnode->pathfile)) + if (pnode && !TAB_HEX_MODE(pnode) && !url_has_remote(pnode->pathfile)) { bool reload = true; bool modified = pnode->be_modify; diff --git a/src/eu_file.h b/src/eu_file.h index a0ed37f6..fa1e7d37 100644 --- a/src/eu_file.h +++ b/src/eu_file.h @@ -20,9 +20,6 @@ #define _H_SKYLARK_FILE_ #define URL_MIN 7 -#define BUFF_SIZE (8 * 1024 * 1024) // 8M -#define BUFF_32K (32 * 1024) // 32K -#define ENABLE_MMAP(x) (x > (uint64_t) 0x8000000) //128M #define file_click_close(m) (m != FILE_AUTO_SAVE && m != FILE_SHUTDOWN && mode != FILE_REMOTE_CLOSE) #define url_has_remote(ll) (_tcslen(ll) > URL_MIN && _tcsnicmp(ll, _T("sftp://"), URL_MIN) == 0) #define url_has_samba(ll) (_tcslen(ll) > 2 && (ll[1] == L'\\' && ll[0] == L'\\')) @@ -58,13 +55,14 @@ typedef struct _file_backup int zoom; int status; int sync; + int view; TCHAR rel_path[MAX_BUFFER]; TCHAR bak_path[MAX_BUFFER]; char mark_id[MAX_BUFFER]; char fold_id[MAX_BUFFER]; }file_backup; -int on_file_new(void); +int on_file_new(eu_tabpage *psrc); int on_file_load(eu_tabpage *pnode, file_backup *pbak, const bool force); int on_file_only_open(file_backup *pbak, const bool selection); int on_file_open(void); @@ -74,14 +72,16 @@ int on_file_open_remote(remotefs *pserver, file_backup *pbak, const bool selecti int on_file_save(eu_tabpage *pnode, const bool save_as); int on_file_save_as(eu_tabpage *pnode); int on_file_all_save(void); -int on_file_close(eu_tabpage *pnode, CLOSE_MODE mode); +int on_file_close(eu_tabpage **ppnode, const CLOSE_MODE mode); int on_file_all_close(void); int on_file_left_close(void); int on_file_right_close(void); int on_file_exclude_close(eu_tabpage *pnode); +int on_file_unchange_close(eu_tabpage *pnode); int on_file_open_filename_dlg(HWND hwnd, TCHAR *file_name, int name_len); int on_file_redirect(HWND hwnd, file_backup *pm); int on_file_stream_upload(eu_tabpage *pnode, TCHAR *pmsg); +int on_file_load_plugins(eu_tabpage *pnode, bool route_open); void on_file_update_time(eu_tabpage *pnode, time_t m); void on_file_new_eols(eu_tabpage *pnode, const int new_eol); void on_file_new_encoding(eu_tabpage *pnode, const int new_enc); @@ -94,6 +94,10 @@ void on_file_restore_recent(void); void on_file_reload_current(eu_tabpage *pnode); void on_file_auto_backup(void); void on_file_auto_notify(void); +void on_file_filedb_update(const eu_tabpage *pnode); +void on_file_npp_write(eu_tabpage *pnode, const wchar_t *cache_path, const bool isbak, int *); +bool on_file_get_bakpath(eu_tabpage *pnode); +bool on_file_map_hex(eu_tabpage *pnode, HANDLE hfile, const size_t nbyte); uint64_t on_file_get_avail_phys(void); #ifdef __cplusplus diff --git a/src/eu_format.c b/src/eu_format.c index f5b64f04..f52282ea 100644 --- a/src/eu_format.c +++ b/src/eu_format.c @@ -481,7 +481,7 @@ on_format_do_compress(eu_tabpage *pnode, format_back fn) size_t txt_len = 0; do { - if (!pnode || !pnode->doc_ptr || pnode->hex_mode || pnode->plugin) + if (!pnode || !pnode->doc_ptr || TAB_HEX_MODE(pnode) || pnode->plugin) { break; } @@ -544,7 +544,7 @@ on_format_clang_file(eu_tabpage *p, const bool whole) do { size_t text_len = 0; - if (!pnode || !pnode->doc_ptr || pnode->hex_mode || pnode->plugin) + if (!pnode || !pnode->doc_ptr || TAB_HEX_MODE(pnode) || pnode->plugin) { break; } @@ -616,7 +616,7 @@ on_format_clang_file(eu_tabpage *p, const bool whole) void on_format_file_style(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod && pnode->doc_ptr) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod && pnode->doc_ptr) { if (pnode->doc_ptr->doc_type == DOCTYPE_JSON || pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT) { @@ -677,7 +677,7 @@ on_format_get_lines(sptr_t *vec_lines, const int vec_size, wchar_t *pstr, const void on_format_check_indentation(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { size_t vec_size = 0; wchar_t *pmsg = NULL; diff --git a/src/eu_hex.c b/src/eu_hex.c index 16ea8baa..f8ee0375 100644 --- a/src/eu_hex.c +++ b/src/eu_hex.c @@ -438,7 +438,7 @@ hexview_update_theme(eu_tabpage *p) { if (p && p->hwnd_sc) { - if (p->hex_mode) + if (TAB_HEX_MODE(p)) { SendMessage(p->hwnd_sc, WM_SETFONT, 0, 0); SendMessage(p->hwnd_sc, HVM_SETTEXTCOLOR, 0, (LPARAM) eu_get_theme()->item.text.color); @@ -484,7 +484,7 @@ hexview_destoy(eu_tabpage *pnode) { eu_safe_free(pnode->phex->pbase); } - pnode->hex_mode = false; + pnode->hex_mode = TAB_HAS_PDF(pnode) ? TYPES_PLUGIN : TYPES_TEXT; eu_safe_free(pnode->phex); } } @@ -1032,14 +1032,7 @@ hexview_proc(HWND hwnd, uint32_t message, WPARAM wParam, LPARAM lParam) break; } case WM_SETFONT: - { - HDC hdc; - TEXTMETRIC text_metric; - HANDLE hold_font; - // - // Delete the font, if we created it by yourself. - // - + { // Delete the font, if we created it by yourself. if ((hexview->ct_flags & HVF_FONTCREATED) && hexview->hfont) { DeleteObject(hexview->hfont); @@ -1050,17 +1043,14 @@ hexview_proc(HWND hwnd, uint32_t message, WPARAM wParam, LPARAM lParam) { hexview_create_font(hwnd, hexview, pnode->zoom_level); } - hdc = GetDC(hwnd); - hold_font = SelectObject(hdc, hexview->hfont); - GetTextMetrics(hdc, &text_metric); - SelectObject(hdc, hold_font); - ReleaseDC(hwnd, hdc); - hexview->width_char = text_metric.tmAveCharWidth; - hexview->height_char = text_metric.tmHeight; - hexview->visiblelines = hexview->height_view / hexview->height_char; - hexview->visiblechars = hexview->width_view / hexview->width_char; - hexview_columns(hexview); - hexview_srollinfo(hwnd, hexview); + if (hexview->hfont) + { + util_font_xy(hwnd, hexview->hfont, &hexview->width_char, &hexview->height_char); + hexview->visiblelines = hexview->height_view / hexview->height_char; + hexview->visiblechars = hexview->width_view / hexview->width_char; + hexview_columns(hexview); + hexview_srollinfo(hwnd, hexview); + } break; } case WM_RBUTTONUP: @@ -1492,7 +1482,7 @@ hexview_proc(HWND hwnd, uint32_t message, WPARAM wParam, LPARAM lParam) } if (GetFocus() != hwnd) { // 可能被plugin窗口强占了键盘焦点 - on_proc_resize(NULL); + eu_window_resize(NULL); } break; } @@ -1944,6 +1934,7 @@ hexview_register_class(void) bool hexview_init(eu_tabpage *pnode) { + HWND hwsc = NULL; HWND hwnd = eu_module_hwnd(); if (!(pnode && hwnd)) { @@ -1955,14 +1946,14 @@ hexview_init(eu_tabpage *pnode) } if (pnode->hwnd_sc) { // 销毁scintilla窗口与其关联窗口, 复用pnode指针 + hwsc = pnode->hwnd_sc; on_sci_destroy_control(pnode); - SendMessage(pnode->hwnd_sc, WM_CLOSE, 0, 0); } if (true) { pnode->eusc = 0; pnode->begin_pos = -1; - pnode->hex_mode = true; + pnode->hex_mode = TYPES_HEX; hexview_register_class(); } if (!(pnode->hwnd_sc = hexview_create_dlg(hwnd, pnode))) @@ -1985,7 +1976,17 @@ hexview_init(eu_tabpage *pnode) } SendMessage(pnode->hwnd_sc, HVM_SETITEMCOUNT, 0, (LPARAM) pnode->bytes_remaining); on_tabpage_selection(pnode, pnode->tab_id); - PostMessage(pnode->hwnd_sc, WM_SETFOCUS, 0, 0); + SendMessage(pnode->hwnd_sc, WM_SETFOCUS, 0, 0); + if (pnode->plugin) + { + np_plugins_destroy(&pnode->plugin->funcs, &pnode->plugin->npp, NULL); + np_plugins_shutdown(&pnode->pmod, &pnode->plugin); + } + if (hwsc) + { + SendMessage(hwsc, WM_CLOSE, 0, 0); + } + eu_close_dll(pnode->pmod); return true; } @@ -2095,7 +2096,7 @@ hexview_save_data(eu_tabpage *pnode, const TCHAR *bakfile) { return EUE_TAB_NULL; } - if (bakfile) + if (STR_NOT_NUL(bakfile)) { if (eu_exist_file(bakfile)) { @@ -2145,10 +2146,57 @@ hexview_strdup_data(eu_tabpage *pnode, size_t *plen) return pstr; } +static bool +hexview_map_pdf(eu_tabpage *pnode) +{ + bool ret = false; + if (pnode) + { + HANDLE hfile = NULL; + TCHAR *pfull = NULL; + if (pnode->be_modify) + { + if ((pnode->bakpath[0] || on_file_get_bakpath(pnode))) + { + int status = 1; + on_file_npp_write(pnode, pnode->bakpath, true, &status); + if (!status) + { + pnode->be_modify = false; + } + if (pnode->be_modify && eu_exist_file(pnode->bakpath)) + { + pfull = _tcsdup(pnode->bakpath); + } + } + } + else if (pnode->plugin) + { // 获取远程文件映射在本地的文件名 + np_plugins_getvalue(&pnode->plugin->funcs, &pnode->plugin->npp, NV_TABTITLE, (void **)&pfull); + } + if (STR_NOT_NUL(pfull)) + { + if (share_open_file(pfull, true, OPEN_EXISTING, &hfile) && util_file_size(hfile, &pnode->bytes_remaining) && pnode->bytes_remaining > 0) + { + ret = on_file_map_hex(pnode, hfile, 0); + } + } + share_close(hfile); + eu_safe_free(pfull); + } + if (ret && pnode && pnode->phex) + { + pnode->phex->hex_ascii = true; + } + return ret; +} + int hexview_switch_mode(eu_tabpage *pnode) { int err = EUE_TAB_NULL; + const bool pdf = TAB_HAS_PDF(pnode); + const HWND search = eu_get_search_hwnd(); uint8_t *pdst = NULL; if (!pnode) { @@ -2159,24 +2207,33 @@ hexview_switch_mode(eu_tabpage *pnode) on_tabpage_active_tab(pnode); } util_lock(&pnode->busy_id); - if (!pnode->hex_mode) + if (!TAB_HEX_MODE(pnode)) { pnode->nc_pos = eu_sci_call(pnode, SCI_GETCURRENTPOS, 0, 0); pnode->zoom_level = (pnode->zoom_level == SELECTION_ZOOM_LEVEEL) ? 0 : (int)eu_sci_call(pnode, SCI_GETZOOM, 0, 0); - eu_logmsg("To hex, pnode->zoom_level = %d\n", pnode->zoom_level); + eu_logmsg("To hex, nc_pos = %I64d, pnode->zoom_level = %d\n", pnode->nc_pos, pnode->zoom_level); if (!pnode->phex) { - pnode->phex = (PHEXVIEW) calloc(1, sizeof(HEXVIEW)); - if (!pnode->phex) + if (!pdf) { - err = EUE_POINT_NULL; - goto HEX_ERROR; + pnode->phex = (PHEXVIEW) calloc(1, sizeof(HEXVIEW)); + if (!pnode->phex) + { + err = EUE_POINT_NULL; + goto HEX_ERROR; + } + if (!(pnode->phex->pbase = (uint8_t *) util_strdup_content(pnode, &pnode->bytes_remaining))) + { + eu_logmsg("%s: txt maybe null\n", __FUNCTION__); + err = EUE_POINT_NULL; + eu_safe_free(pnode->phex); + goto HEX_ERROR; + } } - if (!(pnode->phex->pbase = (uint8_t *) util_strdup_content(pnode, &pnode->bytes_remaining))) + else if (!hexview_map_pdf(pnode)) { - eu_logmsg("%s: txt maybe null\n", __FUNCTION__); - err = EUE_POINT_NULL; - eu_safe_free(pnode->phex); + err = SKYLARK_MEMAP_FAILED; + eu_logmsg("%s: hexview_map_pdf failed\n", __FUNCTION__); goto HEX_ERROR; } if (!hexview_init(pnode)) @@ -2184,14 +2241,18 @@ hexview_switch_mode(eu_tabpage *pnode) err = EUE_CREATE_MAP_ERR; eu_safe_free(pnode->phex->pbase); eu_safe_free(pnode->phex); + eu_logmsg("%s: hexview_init failed\n", __FUNCTION__); goto HEX_ERROR; } - if ((err = pnode->tab_id) >= 0 && pnode->nc_pos >= 0) + if (!pdf) { - eu_sci_call(pnode, SCI_GOTOPOS, pnode->nc_pos, 0); + if ((err = pnode->tab_id) >= 0 && pnode->nc_pos >= 0) + { + eu_sci_call(pnode, SCI_GOTOPOS, pnode->nc_pos, 0); + } + // 清理文本模式下的导航信息 + on_search_clean_navigate_this(pnode); } - // 清理文本模式下的导航信息 - on_search_clean_navigate_this(pnode); } } else @@ -2200,74 +2261,104 @@ hexview_switch_mode(eu_tabpage *pnode) size_t offset = 0; size_t dst_len = 0; bool is_utf8 = pnode->codepage == IDM_UNI_UTF8; - pnode->begin_pos = -1; + const HWND hwsc = pnode->hwnd_sc; + on_search_clean_navigate_this(pnode); pnode->tab_id = on_tabpage_get_index(pnode); - pnode->doc_ptr = on_doc_get_type(pnode->filename); - pnode->nc_pos = pnode->phex ? pnode->phex->number_items : -1; - pnode->zoom_level = (int)eu_sci_call(pnode, SCI_GETZOOM, 0, 0); - pnode->zoom_level == SELECTION_ZOOM_LEVEEL ? (pnode->zoom_level = 0) : (void)0; - eu_logmsg("To text, pnode->zoom_level = %d\n", pnode->zoom_level); - pnode->needpre = pnode->pre_len > 0; - if (pnode->phex && pnode->phex->hex_ascii) - { - is_utf8 = false; - } - else + pnode->raw_size = eu_sci_call(pnode, SCI_GETLENGTH, 0, 0); + if (pdf && np_plugins_lookup(NPP_PDFVIEW, pnode->extname, &pnode->pmod)) { - is_utf8 = true; - } - if (is_utf8) - { - pdst = hexview_strdup_data(pnode, &dst_len); + pnode->hex_mode = TYPES_PLUGIN; + if (on_sci_init_dlg(pnode)) + { + eu_logmsg("%s: on_sci_init_dlg failed\n", __FUNCTION__); + err = EUE_UNKOWN_ERR; + goto HEX_ERROR; + } + if (url_has_remote(pnode->pathfile) || pnode->be_modify) + { + if (pnode->bakpath[0] || on_file_get_bakpath(pnode)) + { + err = hexview_save_data(pnode, pnode->bakpath); + if (err == SKYLARK_OK) + { + eu_logmsg("%s: pnode->raw_size = %I64u\n", __FUNCTION__, pnode->raw_size); + } + } + } + if ((err = on_file_load_plugins(pnode, false)) == NP_NO_ERROR) + { + eu_logmsg("%s: on_file_load_plugins ok\n", __FUNCTION__); + } } - else + else { - size_t src_len = (size_t)pnode->raw_size; - uint8_t *data = pnode->phex->pbase; - euconv_t evd = {0}; - evd.src_from = eu_query_encoding_name(pnode->codepage); - evd.dst_to = "utf-8"; - if (evd.src_from && strcmp(evd.src_from, "UTF-8(BOM)") == 0) + pnode->begin_pos = -1; + pnode->hex_mode = TYPES_TEXT; + pnode->tab_id = on_tabpage_get_index(pnode); + pnode->doc_ptr = on_doc_get_type(pnode->filename); + pnode->nc_pos = pnode->phex ? pnode->phex->number_items : -1; + pnode->zoom_level = (int)eu_sci_call(pnode, SCI_GETZOOM, 0, 0); + pnode->zoom_level == SELECTION_ZOOM_LEVEEL ? (pnode->zoom_level = 0) : (void)0; + eu_logmsg("To text, pnode->zoom_level = %d\n", pnode->zoom_level); + pnode->needpre = pnode->pre_len > 0; + if (!pnode->bakpath[0] && pnode->phex && pnode->phex->hex_ascii) + { + is_utf8 = false; + } + else + { + is_utf8 = true; + } + if (is_utf8) + { + pdst = hexview_strdup_data(pnode, &dst_len); + } + else { - evd.src_from = "utf-8"; + size_t src_len = (size_t)pnode->raw_size; + uint8_t *data = pnode->phex->pbase; + euconv_t evd = {0}; + evd.src_from = eu_query_encoding_name(pnode->codepage); + evd.dst_to = "utf-8"; + if (evd.src_from && strcmp(evd.src_from, "UTF-8(BOM)") == 0) + { + evd.src_from = "utf-8"; + } + eu_logmsg("%s: on_encoding_do_iconv, from %s to %s\n", __FUNCTION__, evd.src_from, evd.dst_to); + size_t res = on_encoding_do_iconv(&evd, (char *) (data), &src_len, &pdst, &dst_len); + if (res == (size_t) -1) + { + eu_logmsg("%s: on_encoding_do_iconv error\n", __FUNCTION__); + err = EUE_ICONV_FAIL; + goto HEX_ERROR; + } + // 保存bom + on_encoding_set_bom(pnode->phex->pbase, pnode); + if (memcmp(pdst, (const uint8_t *) "\xEF\xBB\xBF", 3) == 0) + { // 因为pbase带bom情况下转换为utf8, 会产生bom + // 而我们不需要, 因为前面已经保存了原始文本的bom + offset = 3; + eu_logmsg("we save utf8 bom, offset = 3\n"); + } } - eu_logmsg("%s: on_encoding_do_iconv, from %s to %s\n", __FUNCTION__, evd.src_from, evd.dst_to); - size_t res = on_encoding_do_iconv(&evd, (char *) (data), &src_len, &pdst, &dst_len); - if (res == (size_t) -1) + if (!pdst) { - eu_logmsg("%s: on_encoding_do_iconv error\n", __FUNCTION__); - err = EUE_ICONV_FAIL; + err = EUE_POINT_NULL; goto HEX_ERROR; } - // 保存bom - on_encoding_set_bom(pnode->phex->pbase, pnode); - if (memcmp(pdst, (const uint8_t *) "\xEF\xBB\xBF", 3) == 0) - { // 因为pbase带bom情况下转换为utf8, 会产生bom - // 而我们不需要, 因为前面已经保存了原始文本的bom - offset = 3; - eu_logmsg("we save utf8 bom, offset = 3\n"); + if (on_sci_init_dlg(pnode)) + { + eu_logmsg("on_sci_init_dlg return failed on %s:%d\n", __FILE__, __LINE__); + err = EUE_UNKOWN_ERR; + goto HEX_ERROR; } + on_sci_before_file(pnode, true); + eu_sci_call(pnode, SCI_CLEARALL, 0, 0); + eu_sci_call(pnode, SCI_ADDTEXT, dst_len - offset, (LPARAM)(pdst + offset)); + eu_sci_call(pnode, SCI_SETOVERTYPE, false, 0); + on_sci_after_file(pnode, true); + on_search_add_navigate_list(pnode, 0); } - if (!pdst) - { - err = EUE_POINT_NULL; - goto HEX_ERROR; - } - // 清理16进制编辑器下的导航信息 - on_search_clean_navigate_this(pnode); - SendMessage(pnode->hwnd_sc, WM_CLOSE, 0, 0); - if (on_sci_init_dlg(pnode)) - { - eu_logmsg("on_sci_init_dlg return failed on %s:%d\n", __FILE__, __LINE__); - err = EUE_UNKOWN_ERR; - goto HEX_ERROR; - } - on_sci_before_file(pnode, true); - eu_sci_call(pnode, SCI_CLEARALL, 0, 0); - eu_sci_call(pnode, SCI_ADDTEXT, dst_len - offset, (LPARAM)(pdst + offset)); - eu_sci_call(pnode, SCI_SETOVERTYPE, false, 0); - on_sci_after_file(pnode, true); - on_search_add_navigate_list(pnode, 0); if ((err = on_tabpage_selection(pnode, pnode->tab_id)) >= 0) { if (pnode->nc_pos >= 0) @@ -2279,13 +2370,14 @@ hexview_switch_mode(eu_tabpage *pnode) pnode->file_attr &= ~FILE_READONLY_COLOR; on_statusbar_btn_colour(pnode, true); } - eu_logmsg("%s: pnode->eol = %d\n", __FUNCTION__, pnode->eol); - PostMessage(pnode->hwnd_sc, WM_SETFOCUS, 0, 0); + eu_logmsg("%s: pnode->eol = %d, pnode->hex_mode = %d\n", __FUNCTION__, pnode->eol, pnode->hex_mode); + SendMessage(pnode->hwnd_sc, WM_SETFOCUS, 0, 0); + SendMessage(hwsc, WM_CLOSE, 0, 0); } } HEX_ERROR: eu_safe_free(pdst); - ShowWindow(eu_get_search_hwnd(), SW_HIDE); + search ? ShowWindow(search, SW_HIDE) : (void)0; util_unlock(&pnode->busy_id); return err; } diff --git a/src/eu_locale.c b/src/eu_locale.c index 83a3aa0f..420fa1ba 100644 --- a/src/eu_locale.c +++ b/src/eu_locale.c @@ -337,10 +337,6 @@ eu_refresh_interface(HMODULE new_lang, const TCHAR *lang_path) } DestroyWindow(on_toolbar_clip_hwnd()); } - if (g_statusbar) - { // 销毁状态栏 - DestroyWindow(g_statusbar); - } if (true) { // 更新全局变量与共享内存 FreeLibrary(g_skylark_lang); @@ -353,9 +349,9 @@ eu_refresh_interface(HMODULE new_lang, const TCHAR *lang_path) { return 1; } - if (on_toolbar_create(hwnd) != 0) + if (on_toolbar_create_dlg(hwnd) != 0) { - eu_logmsg("on_toolbar_create return false\n"); + eu_logmsg("on_toolbar_create_dlg return false\n"); return 1; } if (on_treebar_create_box(hwnd)) @@ -376,15 +372,18 @@ eu_refresh_interface(HMODULE new_lang, const TCHAR *lang_path) ShowWindow(hcip, SW_SHOW); } } - if (!on_statusbar_init(eu_module_hwnd())) + if (on_statusbar_create_dlg(eu_module_hwnd())) { eu_logmsg("on_statusbar_init return false\n"); return 1; } - else if (!on_dark_enable()) + else { - SendMessage(g_statusbar, WM_STATUS_REFRESH, 0, 0); - on_statusbar_update(); + on_statusbar_size(NULL); + if (on_dark_enable()) + { + SendMessage(g_statusbar, WM_THEMECHANGED, 0, 0); + } } on_favorite_reload_root(); on_search_dark_mode_release(); diff --git a/src/eu_main.c b/src/eu_main.c index 918f7667..e8072eaa 100644 --- a/src/eu_main.c +++ b/src/eu_main.c @@ -41,14 +41,6 @@ init_instance(HINSTANCE instance) HWND hwnd = eu_create_main_window(instance); if (hwnd) { - if (!eu_create_toolbar(hwnd)) - { - return NULL; - } - if (!eu_create_statusbar(hwnd)) - { - return NULL; - } if (eu_get_config()->m_fullscreen) { eu_logmsg("we create fullsrceen window\n"); @@ -226,6 +218,7 @@ _tmain(int argc, TCHAR *argv[]) } else if (!EU_REENTRANT_PARAM) { + eu_wine_dotool(); SKY_SAFE_EXIT(SKYLARK_OK); } } @@ -282,6 +275,13 @@ _tmain(int argc, TCHAR *argv[]) eu_logmsg("eu_sci_register failed\n"); SKY_SAFE_EXIT(SKYLARK_SCI_FAILED); } + if (!eu_win11_or_later() && strcmp(eu_get_config()->window_theme, "black") == 0) + { + if (eu_dark_theme_init(true, true)) + { + eu_logmsg("eu_dark_theme_init ok!\n"); + } + } if (!(hwnd = init_instance(instance))) { eu_logmsg("init_instance failed\n"); @@ -298,23 +298,27 @@ _tmain(int argc, TCHAR *argv[]) share_unmap(phandle); } } - share_envent_set(true); // 主窗口初始化完成, 可以发送消息了 if (no_remote) { eu_get_config()->m_instance = true; } + if (true) + { // 主窗口初始化完成的信号量 + share_envent_set(true); + } if (!eu_config_load_files()) { eu_logmsg("eu_config_load_files failed\n"); SKY_SAFE_EXIT(SKYLARK_CONF_FAILED); } } - if (strcmp(eu_get_config()->window_theme, "black") == 0) + if (eu_dark_enable()) { - if (eu_dark_theme_init(true, true)) - { - SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_NORMAL, 10, 0); - } + SendMessage(eu_module_hwnd(), WM_THEMECHANGED, DARK_THEME_APPLY, 0); + } + else if (eu_win11_or_later() && strcmp(eu_get_config()->window_theme, "black") == 0 && eu_dark_theme_init(true, true)) + { + SendMessage(eu_module_hwnd(), WM_THEMECHANGED, DARK_THEME_APPLY, 0); } while (GetMessage(&msg, NULL, 0, 0) > 0) { diff --git a/src/eu_menu.c b/src/eu_menu.c index b9e7e770..e43d58ff 100644 --- a/src/eu_menu.c +++ b/src/eu_menu.c @@ -188,14 +188,11 @@ menu_update_hexview(const HMENU root_menu, const bool hex_mode, const bool init) util_enable_menu_item(root_menu, IDM_EDIT_PLACEHOLDE12, init || !hex_mode); util_enable_menu_item(root_menu, IDM_EDIT_PLACEHOLDE13, init || !hex_mode); util_enable_menu_item(root_menu, IDM_SEARCH_REPLACE, init || !hex_mode); - util_enable_menu_item(root_menu, IDM_SELECTION_RECTANGLE, init || !hex_mode); util_enable_menu_item(root_menu, IDM_SEARCH_MULTISELECT_README, init || !hex_mode); util_enable_menu_item(root_menu, IDM_VIEW_TAB_WIDTH, init || !hex_mode); util_enable_menu_item(root_menu, IDM_TAB_CONVERT_SPACES, init || !hex_mode); util_enable_menu_item(root_menu, IDM_VIEW_DOCUMENT_MAP, init || !hex_mode); - util_enable_menu_item(root_menu, IDM_VIEW_HIGHLIGHT_BRACE, init || !hex_mode); - util_enable_menu_item(root_menu, IDM_VIEW_HIGHLIGHT_STR, init || !hex_mode); - util_enable_menu_item(root_menu, IDM_VIEW_HIGHLIGHT_FOLD, init || !hex_mode); + util_enable_menu_item(root_menu, IDM_VIEW_HIGHLIGHT_GROUP, init || !hex_mode); util_enable_menu_item(root_menu, IDM_VIEW_CODE_HINT, init || !hex_mode); util_enable_menu_item(root_menu, IDM_EDIT_AUTO_INDENTATION, init || !hex_mode); util_enable_menu_item(root_menu, IDM_VIEW_LINENUMBER_VISIABLE, init || !hex_mode); @@ -213,6 +210,7 @@ menu_update_hexview(const HMENU root_menu, const bool hex_mode, const bool init) util_enable_menu_item(root_menu, IDM_SETTING_RENDER, init || !hex_mode); util_enable_menu_item(root_menu, IDM_VIEW_HISTORY_PLACEHOLDE, init || !hex_mode); util_enable_menu_item(root_menu, IDM_SEARCH_HISTORY_PLACEHOLDE, init || !hex_mode); + util_enable_menu_item(root_menu, IDM_VIEW_SCROLLCURSOR, init || !hex_mode); } } @@ -384,10 +382,9 @@ menu_update_string(const HMENU hmenu, const int pos) return id; } -static unsigned __stdcall -menu_setup_thead(void* lp) +void +menu_setup(HWND hwnd) { - HWND hwnd = (HWND)lp; if (hwnd && SetMenu(hwnd, i18n_load_menu(IDC_SKYLARK))) { HMENU root_menu = GetMenu(hwnd); @@ -398,13 +395,6 @@ menu_setup_thead(void* lp) SetMenu(hwnd, NULL); } } - return 0; -} - -void -menu_setup(HWND hwnd) -{ - CloseHandle((HANDLE) _beginthreadex(NULL, 0, menu_setup_thead, (void *)hwnd, 0, NULL)); } void @@ -417,16 +407,19 @@ menu_update_item(const HMENU menu, const bool init) if (count > 0 && eu_get_config() && pnode) { int enable = 0; - menu_update_hexview(menu, pnode->hex_mode, init); + menu_update_hexview(menu, TAB_HEX_MODE(pnode) || TAB_HAS_PDF(pnode), init); for (int i = 0; i < count; ++i) { uint32_t m_id = menu_update_string(menu, i); switch (m_id) { case IDM_HISTORY_BASE: + { on_file_update_recent_menu(); break; + } case IDM_FILE_EXIT_WHEN_LAST_TAB: /* File menu */ + { util_enable_menu_item(menu, IDM_FILE_SAVE, init || (on_sci_doc_modified(pnode) && !(pnode->file_attr & FILE_ATTRIBUTE_READONLY))); util_enable_menu_item(menu, IDM_FILE_SAVEAS, init || pnode->filename[0]); util_enable_menu_item(menu, IDM_FILE_REMOTE_FILESERVERS, init || util_exist_libcurl()); @@ -434,62 +427,89 @@ menu_update_item(const HMENU menu, const bool init) util_set_menu_item(menu, IDM_FILE_SESSION, eu_get_config()->m_session); util_set_menu_item(menu, IDM_FILE_EXIT_WHEN_LAST_TAB, eu_get_config()->m_exit); break; + } case IDM_FILE_NEWFILE_WINDOWS_EOLS: + { util_set_menu_item(menu, IDM_FILE_NEWFILE_WINDOWS_EOLS, (eu_get_config()->new_file_eol == 0)); util_set_menu_item(menu, IDM_FILE_NEWFILE_MAC_EOLS, (eu_get_config()->new_file_eol == 1)); util_set_menu_item(menu, IDM_FILE_NEWFILE_UNIX_EOLS, (eu_get_config()->new_file_eol == 2)); break; + } case IDM_FILE_NEWFILE_ENCODING_UTF8: + { util_set_menu_item(menu, IDM_FILE_NEWFILE_ENCODING_UTF8, (eu_get_config()->new_file_enc == IDM_UNI_UTF8)); util_set_menu_item(menu, IDM_FILE_NEWFILE_ENCODING_UTF8B, (eu_get_config()->new_file_enc == IDM_UNI_UTF8B)); util_set_menu_item(menu, IDM_FILE_NEWFILE_ENCODING_UTF16LE, (eu_get_config()->new_file_enc == IDM_UNI_UTF16LEB)); util_set_menu_item(menu, IDM_FILE_NEWFILE_ENCODING_UTF16BE, (eu_get_config()->new_file_enc == IDM_UNI_UTF16BEB)); util_set_menu_item(menu, IDM_FILE_NEWFILE_ENCODING_ANSI, (eu_get_config()->new_file_enc == IDM_OTHER_ANSI)); break; + } case IDM_FILE_RELOAD_CURRENT: - util_enable_menu_item(menu, IDM_FILE_RELOAD_CURRENT, pnode && !pnode->hex_mode && !url_has_remote(pnode->pathfile)); + { + util_enable_menu_item(menu, IDM_FILE_RELOAD_CURRENT, pnode && !TAB_HEX_MODE(pnode) && !url_has_remote(pnode->pathfile)); break; + } case IDM_FILE_ADD_FAVORITES: + { util_enable_menu_item(menu, IDM_FILE_ADD_FAVORITES, init || !pnode->is_blank); + break; + } case IDM_FILE_RESTART_ADMIN: + { init ? (void)0 : menu_shield_icons(menu, IDM_FILE_RESTART_ADMIN, IDM_FILE_RESTART_ADMIN); util_enable_menu_item(menu, IDM_FILE_RESTART_ADMIN, init || !util_under_wine()); break; + } case IDM_EDIT_UNDO: /* Edit menu */ case IDM_EDIT_REDO: + { util_enable_menu_item(menu, IDM_EDIT_UNDO, init || eu_sci_call(pnode,SCI_CANUNDO, 0, 0)); util_enable_menu_item(menu, IDM_EDIT_REDO, init || eu_sci_call(pnode,SCI_CANREDO, 0, 0)); break; + } case IDM_EDIT_CUT: case IDM_EDIT_COPY: case IDM_EDIT_PASTE: case IDM_EDIT_DELETE: - util_enable_menu_item(menu, IDM_EDIT_CUT, init || (!pnode->plugin && (pnode->hex_mode || util_can_selections(pnode)))); + { + util_enable_menu_item(menu, IDM_EDIT_CUT, init || (!pnode->plugin && (TAB_HEX_MODE(pnode) || util_can_selections(pnode)))); util_enable_menu_item(menu, IDM_EDIT_COPY, init || (!pnode->pmod && TAB_NOT_NUL(pnode))); util_enable_menu_item(menu, IDM_EDIT_PASTE, init || !pnode->plugin); util_enable_menu_item(menu, IDM_EDIT_DELETE, init || (!pnode->plugin && TAB_NOT_NUL(pnode))); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE2, init || (!pnode->hex_mode && TAB_NOT_NUL(pnode))); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE5, init || (!pnode->hex_mode && TAB_NOT_NUL(pnode))); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE6, init || (!pnode->hex_mode && TAB_NOT_NUL(pnode))); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE2, init || (!TAB_HEX_MODE(pnode) && TAB_NOT_NUL(pnode))); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE5, init || (!TAB_HEX_MODE(pnode) && TAB_NOT_NUL(pnode))); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE6, init || (!TAB_HEX_MODE(pnode) && TAB_NOT_NUL(pnode))); util_enable_menu_item(menu, IDM_EDIT_SELECT_GROUP, init || util_can_selections(pnode)); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE7, init || (!pnode->hex_mode && eu_exist_libssl() && util_can_selections(pnode))); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE8, init || (!pnode->hex_mode && eu_exist_libssl() && util_can_selections(pnode))); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE9, init || (!pnode->hex_mode && eu_exist_libssl() && util_can_selections(pnode))); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE7, init || (!TAB_HEX_MODE(pnode) && eu_exist_libssl() && util_can_selections(pnode))); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE8, init || (!TAB_HEX_MODE(pnode) && eu_exist_libssl() && util_can_selections(pnode))); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE9, init || (!TAB_HEX_MODE(pnode) && eu_exist_libssl() && util_can_selections(pnode))); break; + } case IDM_EDIT_COPY_INCREMENTAL: + { util_enable_menu_item(menu, IDM_EDIT_COPY_INCREMENTAL, init || (!pnode->plugin && TAB_NOT_NUL(pnode))); + break; + } case IDM_EDIT_COPY_RTF: - util_enable_menu_item(menu, IDM_EDIT_COPY_RTF, init || (!pnode->hex_mode && !pnode->plugin && TAB_NOT_NUL(pnode))); + { + util_enable_menu_item(menu, IDM_EDIT_COPY_RTF, init || (!TAB_HEX_MODE(pnode) && !pnode->plugin && TAB_NOT_NUL(pnode))); break; + } case IDM_EDIT_SWAP_CLIPBOARD: - util_enable_menu_item(menu, IDM_EDIT_SWAP_CLIPBOARD, init || (!pnode->hex_mode && !pnode->plugin && eu_sci_call(pnode, SCI_CANPASTE, 0, 0))); + { + util_enable_menu_item(menu, IDM_EDIT_SWAP_CLIPBOARD, init || (!TAB_HEX_MODE(pnode) && !pnode->plugin && eu_sci_call(pnode, SCI_CANPASTE, 0, 0))); break; + } case IDM_EDIT_CLEAR_CLIPBOARD: + { util_enable_menu_item(menu, IDM_EDIT_CLEAR_CLIPBOARD, init || on_edit_can_paste()); break; + } case IDM_EDIT_OTHER_EDITOR: + { util_enable_menu_item(menu, IDM_EDIT_OTHER_EDITOR, init || (!pnode->plugin && !pnode->is_blank)); break; + } case IDM_EDIT_OTHER_BCOMPARE: { int num = on_tabpage_sel_number(NULL, false); @@ -499,33 +519,44 @@ menu_update_item(const HMENU menu, const bool init) case IDM_EDIT_SLASH_BACKSLASH: case IDM_EDIT_BACKSLASH_SLASH: { - enable = !pnode->hex_mode && !pnode->plugin && TAB_NOT_NUL(pnode) && util_can_selections(pnode); + enable = !TAB_HEX_MODE(pnode) && !pnode->plugin && TAB_NOT_NUL(pnode) && util_can_selections(pnode); util_enable_menu_item(menu, IDM_EDIT_SLASH_BACKSLASH, init || enable); util_enable_menu_item(menu, IDM_EDIT_BACKSLASH_SLASH, init || enable); } case IDM_UPDATE_SELECTION: /* Search menu */ + { util_set_menu_item(menu, IDM_UPDATE_SELECTION, pnode->begin_pos >= 0); + break; + } + case IDM_SELECTION_RECTANGLE: + { util_set_menu_item(menu, IDM_SELECTION_RECTANGLE, eu_sci_call(pnode, SCI_GETSELECTIONMODE, 0, 0) > 0); + util_enable_menu_item(menu, IDM_SELECTION_RECTANGLE, init || (!TAB_HEX_MODE(pnode) && !pnode->plugin)); break; + } case IDM_SEARCH_MATCHING_BRACE: case IDM_SEARCH_MATCHING_BRACE_SELECT: { on_search_jmp_matching_brace(pnode, &enable); util_enable_menu_item(menu, IDM_SEARCH_MATCHING_BRACE, init || enable); util_enable_menu_item(menu, IDM_SEARCH_MATCHING_BRACE_SELECT, init || enable); + util_enable_menu_item(menu, IDM_SEARCH_SELECT_MATCHING_ALL, init || (!TAB_HEX_MODE(pnode) && !pnode->plugin && TAB_NOT_NUL(pnode))); + util_enable_menu_item(menu, IDM_EDIT_GOLINE_GROUP, init || !pnode->plugin); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE14, init || !pnode->plugin); break; } - case IDM_VIEW_SCROLLCURSOR: /* View menu */ + case IDM_EDIT_AUTO_INDENTATION: /* View menu */ { util_set_menu_item(menu, IDM_VIEW_FILETREE, eu_get_config()->m_ftree_show); - util_set_menu_item(menu, IDM_VIEW_DOCUMENT_MAP, pnode->map_show); + util_set_menu_item(menu, IDM_VIEW_DOCUMENT_MAP, pnode->map_show && hwnd_document_map); util_set_menu_item(menu, IDM_VIEW_SYMTREE, pnode->sym_show); util_enable_menu_item(menu, IDM_VIEW_SYMTREE, init || pnode->hwnd_symlist || pnode->hwnd_symtree); util_set_menu_item(GetSubMenu(menu, TAB_MENU_PANELS_SUB), IDM_VIEW_FULLSCREEN, eu_get_config()->m_fullscreen); util_set_menu_item(GetSubMenu(menu, TAB_MENU_PANELS_SUB), IDM_VIEW_MENUBAR, eu_get_config()->m_menubar); + util_set_menu_item(GetSubMenu(menu, TAB_MENU_PANELS_SUB), IDM_VIEW_TOOLBAR, eu_get_config()->m_toolbar != IDB_SIZE_0); util_set_menu_item(GetSubMenu(menu, TAB_MENU_PANELS_SUB), IDM_VIEW_STATUSBAR, eu_get_config()->m_statusbar); util_set_menu_item(GetSubMenu(menu, TAB_MENU_HILIGHT_SUB), IDM_VIEW_HIGHLIGHT_BRACE, eu_get_config()->eu_brace.matching); - util_set_menu_item(GetSubMenu(menu, TAB_MENU_HILIGHT_SUB), IDM_VIEW_HIGHLIGHT_STR, eu_get_config()->m_light_str); + util_set_menu_item(GetSubMenu(menu, TAB_MENU_HILIGHT_SUB), IDM_VIEW_HIGHLIGHT_STR, eu_get_config()->m_light_str && pnode->raw_size < BUFF_32M); util_set_menu_item(GetSubMenu(menu, TAB_MENU_HILIGHT_SUB), IDM_VIEW_HIGHLIGHT_FOLD, eu_get_config()->light_fold); util_set_menu_item(GetSubMenu(menu, TAB_DISPLAY_SUB), IDM_VIEW_LINENUMBER_VISIABLE, eu_get_config()->m_linenumber); util_set_menu_item(GetSubMenu(menu, TAB_DISPLAY_SUB), IDM_VIEW_BOOKMARK_VISIABLE, eu_get_config()->eu_bookmark.visable); @@ -536,10 +567,10 @@ menu_update_item(const HMENU menu, const bool init) util_set_menu_item(GetSubMenu(menu, TAB_DISPLAY_SUB), IDM_VIEW_CODE_HINT, eu_get_config()->m_code_hint); enable = eu_get_config()->block_fold && pnode->foldline; util_set_menu_item(GetSubMenu(menu, TAB_DISPLAY_SUB), IDM_VIEW_FOLDLINE_VISIABLE, enable); - util_enable_menu_item(GetSubMenu(menu, TAB_DISPLAY_SUB), IDM_VIEW_FOLDLINE_VISIABLE, init || (!pnode->hex_mode && !pnode->plugin && pnode->foldline)); + util_enable_menu_item(GetSubMenu(menu, TAB_DISPLAY_SUB), IDM_VIEW_FOLDLINE_VISIABLE, init || (!TAB_HEX_MODE(pnode) && !pnode->plugin && pnode->foldline)); util_set_menu_item(menu, IDM_EDIT_AUTO_INDENTATION, eu_get_config()->m_ident); - util_set_menu_item(menu, IDM_VIEW_HEXEDIT_MODE, pnode->hex_mode); - util_enable_menu_item(menu, IDM_VIEW_HEXEDIT_MODE, init || (pnode->codepage != IDM_OTHER_BIN && TAB_NOT_NUL(pnode))); + util_set_menu_item(menu, IDM_VIEW_HEXEDIT_MODE, TAB_HEX_MODE(pnode)); + util_enable_menu_item(menu, IDM_VIEW_HEXEDIT_MODE, init || (TAB_NOT_BIN(pnode) && (TAB_HAS_PDF(pnode) || TAB_NOT_NUL(pnode)))); if (pnode->doc_ptr) { util_update_menu_chars(menu, IDM_VIEW_TAB_WIDTH, pnode->doc_ptr->tab_width > 0 ? pnode->doc_ptr->tab_width : eu_get_config()->tab_width); @@ -553,86 +584,101 @@ menu_update_item(const HMENU menu, const bool init) util_set_menu_item(GetSubMenu(menu, TAB_MENU_TITLEBAR_SUB), IDM_VIEW_TITLEBAR_ICON, eu_get_config()->eu_titlebar.icon); util_set_menu_item(GetSubMenu(menu, TAB_MENU_TITLEBAR_SUB), IDM_VIEW_TITLEBAR_NAME, eu_get_config()->eu_titlebar.name); util_set_menu_item(GetSubMenu(menu, TAB_MENU_TITLEBAR_SUB), IDM_VIEW_TITLEBAR_PATH, eu_get_config()->eu_titlebar.path); + enable = util_under_wine(); + util_enable_menu_item(menu, IDM_VIEW_TITLEBAR_ICON, init || !enable); + util_enable_menu_item(menu, IDM_VIEW_TITLEBAR_NAME, init || !enable); util_switch_menu_group(menu, TAB_HISTORY_SUB, IDM_VIEW_HISTORY_NONE, IDM_VIEW_HISTORY_ALL, eu_get_config()->history_mask); util_switch_menu_group(menu, TAB_MENU_TOOLBAR_SUB, IDB_SIZE_0, IDB_SIZE_128, eu_get_config()->m_toolbar); util_switch_menu_group(menu, TAB_MENU_ACTIVE_SUB, IDM_VIEW_LEFT_TAB, IDM_VIEW_FAR_RIGHT_TAB, eu_get_config()->m_tab_active); util_switch_menu_group(menu, TAB_MENU_CLOSE_SUB, IDM_VIEW_TAB_RIGHT_CLICK, IDM_VIEW_TAB_LEFT_DBCLICK, eu_get_config()->m_close_way); util_switch_menu_group(menu, TAB_MENU_NEW_SUB, IDM_VIEW_TAB_RIGHT_NEW, IDM_VIEW_TAB_DBCLICK_NEW, eu_get_config()->m_new_way); util_switch_menu_group(menu, TAB_MENU_CBUTTON_SUB, IDM_TABCLOSE_FOLLOW, IDM_TABCLOSE_NONE, eu_get_config()->m_close_draw); - util_set_menu_item(menu, IDM_VIEW_SCROLLCURSOR, eu_get_config()->scroll_to_cursor); - break; - } - case IDM_VIEW_SWITCH_TAB: - { util_enable_menu_item(menu, IDM_VIEW_SWITCH_TAB, init || (g_tabpages && TabCtrl_GetItemCount(g_tabpages) > 1)); + util_set_menu_item(menu, IDM_VIEW_SCROLLCURSOR, eu_get_config()->scroll_to_cursor); + util_set_menu_item(menu, IDM_VIEW_TABBAR_SPLIT, eu_get_config()-> m_tab_split); break; } case IDM_VIEW_WRAPLINE_MODE: /* Format menu */ { enable = eu_exist_file(CLANGDLL); util_set_menu_item(menu, IDM_VIEW_WRAPLINE_MODE, eu_get_config()->line_mode); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_JSON, init || (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_JSON && enable)); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_JS, init || (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT && enable)); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_JSON, init || (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && + pnode->doc_ptr->doc_type == DOCTYPE_JSON && enable)); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_JS, init || (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && + pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT && enable)); util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_CLANG, init || ( - (pnode->doc_ptr && !pnode->hex_mode && enable && + (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && enable && (pnode->doc_ptr->doc_type == DOCTYPE_CPP || pnode->doc_ptr->doc_type == DOCTYPE_CS || pnode->doc_ptr->doc_type == DOCTYPE_VERILOG || pnode->doc_ptr->doc_type == DOCTYPE_JAVA || pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT || pnode->doc_ptr->doc_type == DOCTYPE_JSON)))); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_XML, init ||(pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_XML)); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_LUA, init ||(pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_LUA)); - util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_ICODE, init || (!pnode->hex_mode && !pnode->plugin && TAB_NOT_NUL(pnode))); - util_enable_menu_item(menu, IDM_FORMAT_PLACEHOLDE_PUNCTUATION, init || (!pnode->hex_mode && !pnode->plugin && TAB_NOT_NUL(pnode))); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_XML, init ||(pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->doc_ptr->doc_type == DOCTYPE_XML)); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_LUA, init ||(pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->doc_ptr->doc_type == DOCTYPE_LUA)); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_ICODE, init || (!TAB_HEX_MODE(pnode) && !pnode->plugin && TAB_NOT_NUL(pnode))); + util_enable_menu_item(menu, IDM_FORMAT_PLACEHOLDE_PUNCTUATION, init || (!TAB_HEX_MODE(pnode) && !pnode->plugin && TAB_NOT_NUL(pnode))); break; } case IDM_FORMAT_HYPERLINKHOTSPOTS: { util_set_menu_item(menu, IDM_FORMAT_HYPERLINKHOTSPOTS, eu_get_config()->m_hyperlink); - util_enable_menu_item(menu, IDM_FORMAT_HYPERLINKHOTSPOTS, init || (!pnode->hex_mode && !pnode->plugin && TAB_NOT_NUL(pnode))); + util_enable_menu_item(menu, IDM_FORMAT_HYPERLINKHOTSPOTS, init || (!TAB_HEX_MODE(pnode) && !pnode->plugin && TAB_NOT_NUL(pnode))); break; } case IDM_FORMAT_CHECK_INDENTATION: { - util_enable_menu_item(menu, IDM_FORMAT_CHECK_INDENTATION, init || (!pnode->hex_mode && !pnode->plugin && TAB_NOT_NUL(pnode))); + util_enable_menu_item(menu, IDM_FORMAT_CHECK_INDENTATION, init || (!TAB_HEX_MODE(pnode) && !pnode->plugin && TAB_NOT_NUL(pnode))); break; } case IDM_EDIT_QRCODE: + { util_enable_menu_item(menu, IDM_EDIT_QRCODE, init || (!pnode->plugin && util_can_selections(pnode))); break; + } case IDM_SOURCE_BLOCKFOLD_TOGGLE: /* Programming menu */ case IDM_SOURCE_BLOCKFOLD_CONTRACTALL: case IDM_SOURCE_BLOCKFOLD_EXPANDALL: - enable = eu_get_config()->block_fold && pnode->foldline && !pnode->hex_mode && !pnode->plugin && TAB_NOT_NUL(pnode); + { + enable = eu_get_config()->block_fold && pnode->foldline && !TAB_HEX_MODE(pnode) && !pnode->plugin && TAB_NOT_NUL(pnode); util_enable_menu_item(menu, IDM_SOURCE_BLOCKFOLD_TOGGLE, init || enable); util_enable_menu_item(menu, IDM_SOURCE_BLOCKFOLD_CONTRACTALL, init || enable); util_enable_menu_item(menu, IDM_SOURCE_BLOCKFOLD_EXPANDALL, init || enable); break; + } case IDM_SOURCECODE_GOTODEF: - enable = pnode->doc_ptr && !pnode->hex_mode && pnode->hwnd_symlist; + { + enable = pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->hwnd_symlist; util_enable_menu_item(menu, IDM_SOURCECODE_GOTODEF, init || enable); break; + } case IDM_EDIT_AUTO_CLOSECHAR: + { util_set_menu_item(menu, IDM_EDIT_AUTO_CLOSECHAR, eu_get_config()->eu_brace.autoc); util_set_menu_item(menu, IDM_SOURCEE_ENABLE_ACSHOW, eu_get_config()->eu_complete.enable); util_update_menu_chars(menu, IDM_SOURCEE_ACSHOW_CHARS, eu_get_config()->eu_complete.characters); util_set_menu_item(menu, IDM_SOURCE_ENABLE_CTSHOW, eu_get_config()->eu_calltip.enable); break; + } case IDM_DATABASE_INSERT_CONFIG: case IDM_DATABASE_EXECUTE_SQL: - enable = pnode->doc_ptr && !pnode->hex_mode && (pnode->doc_ptr->doc_type == DOCTYPE_SQL||pnode->doc_ptr->doc_type == DOCTYPE_REDIS); + { + enable = pnode->doc_ptr && !TAB_HEX_MODE(pnode) && (pnode->doc_ptr->doc_type == DOCTYPE_SQL||pnode->doc_ptr->doc_type == DOCTYPE_REDIS); util_enable_menu_item(menu, IDM_DATABASE_INSERT_CONFIG, init || enable); util_enable_menu_item(menu, IDM_DATABASE_EXECUTE_SQL, init || enable); util_switch_menu_group(menu, PROGRAM_SNIPPET_SUB, IDM_SOURCE_SNIPPET_ENABLE, IDM_SOURCE_SNIPPET_ENABLE, eu_get_config()->eu_complete.snippet); - util_enable_menu_item(menu, IDM_EDIT_COMMENT_GROUP, init || (!pnode->hex_mode && pnode->doc_ptr && TAB_NOT_NUL(pnode))); - util_enable_menu_item(menu, IDM_SOURCE_SNIPPET_GROUP, init || (!pnode->hex_mode && pnode->doc_ptr)); + util_enable_menu_item(menu, IDM_EDIT_COMMENT_GROUP, init || (!TAB_HEX_MODE(pnode) && pnode->doc_ptr && TAB_NOT_NUL(pnode))); + util_enable_menu_item(menu, IDM_SOURCE_SNIPPET_GROUP, init || (!TAB_HEX_MODE(pnode) && pnode->doc_ptr)); break; + } case IDM_PROGRAM_EXECUTE_ACTION: - enable = pnode->doc_ptr && !pnode->hex_mode && TAB_NOT_NUL(pnode); + { + enable = pnode->doc_ptr && !TAB_HEX_MODE(pnode) && TAB_NOT_NUL(pnode); util_enable_menu_item(menu, IDM_PROGRAM_EXECUTE_ACTION, init || enable); break; + } case IDM_ENV_FILE_POPUPMENU: /* Settings menu */ + { on_reg_update_menu(); i18n_update_multi_lang(menu); i18n_update_menu(menu); @@ -647,37 +693,55 @@ menu_update_item(const HMENU menu, const bool init) on_setting_update_menu(menu); } break; + } case IDM_VIEW_FONTQUALITY_NONE: + { util_set_menu_item(menu, IDM_VIEW_FONTQUALITY_NONE, IDM_VIEW_FONTQUALITY_NONE == eu_get_config()->m_quality); util_set_menu_item(menu, IDM_VIEW_FONTQUALITY_STANDARD, IDM_VIEW_FONTQUALITY_STANDARD == eu_get_config()->m_quality); util_set_menu_item(menu, IDM_VIEW_FONTQUALITY_CLEARTYPE, IDM_VIEW_FONTQUALITY_CLEARTYPE == eu_get_config()->m_quality); break; + } case IDM_SET_RENDER_TECH_GDI: + { util_set_menu_item(menu, IDM_SET_RENDER_TECH_GDI, IDM_SET_RENDER_TECH_GDI == eu_get_config()->m_render); util_set_menu_item(menu, IDM_SET_RENDER_TECH_D2D, IDM_SET_RENDER_TECH_D2D == eu_get_config()->m_render); util_set_menu_item(menu, IDM_SET_RENDER_TECH_D2DRETAIN, IDM_SET_RENDER_TECH_D2DRETAIN == eu_get_config()->m_render); break; + } case IDM_SET_RESET_CONFIG: + { util_enable_menu_item(menu, IDM_SET_RESET_CONFIG, init || (eu_hwnd_self() == share_envent_get_hwnd())); break; + } case IDM_SET_LOGGING_ENABLE: + { util_set_menu_item(menu, IDM_SET_LOGGING_ENABLE, eu_get_config()->m_logging); break; + } case IDM_FILE_SAVE_NOTIFY: + { + enable = (TAB_NOT_BIN(pnode) && !TAB_HAS_PDF(pnode) && eu_hwnd_self() == share_envent_get_hwnd()); util_update_menu_chars(menu, IDM_FILE_SAVE_NOTIFY, eu_get_config()->m_up_notify); util_set_menu_item(menu, IDM_FILE_SAVE_NOTIFY, eu_get_config()->m_session && eu_get_config()->m_up_notify > 0); - util_enable_menu_item(menu, IDM_FILE_SAVE_NOTIFY, init || (!pnode->hex_mode && eu_hwnd_self() == share_envent_get_hwnd())); + util_enable_menu_item(menu, IDM_FILE_SAVE_NOTIFY, init || enable); break; + } case IDM_SKYLAR_AUTOMATIC_UPDATE: + { enable = util_upcheck_exist(); util_enable_menu_item(menu, IDM_SKYLAR_AUTOMATIC_UPDATE, init || (eu_hwnd_self() == share_envent_get_hwnd() && enable)); util_set_menu_item(menu, IDM_SKYLAR_AUTOMATIC_UPDATE, eu_get_config()->upgrade.enable && enable); break; + } case IDM_ABOUT: /* Help menu */ + { util_enable_menu_item(menu, IDM_DONATION, init || util_exist_libcurl()); break; + } default: + { break; + } } } } diff --git a/src/eu_menu.h b/src/eu_menu.h index b350ac93..c44a3f27 100644 --- a/src/eu_menu.h +++ b/src/eu_menu.h @@ -36,7 +36,7 @@ #define TAB_MENU_CLOSE_SUB 20 #define TAB_MENU_NEW_SUB 21 #define TAB_MENU_CBUTTON_SUB 22 -#define TAB_MENU_SCROLLCURSOR 24 +#define TAB_MENU_OTHER 23 #define PROGRAM_SNIPPET_SUB 15 #define CUSTOMIZED_CMD_SUB 14 diff --git a/src/eu_print.c b/src/eu_print.c index 83f900d2..3ee5b633 100644 --- a/src/eu_print.c +++ b/src/eu_print.c @@ -821,7 +821,7 @@ on_print_file(eu_tabpage *pnode) { np_plugins_print(&pnode->plugin->funcs, &pnode->plugin->npp, NULL); } - else if (!pnode->hex_mode) + else if (!TAB_HEX_MODE(pnode)) { SHFILEINFO shfi = {0}; on_print_file_info(pnode->pathfile, 0, &shfi, sizeof(SHFILEINFO), SHGFI_DISPLAYNAME); diff --git a/src/eu_proc.c b/src/eu_proc.c index 55949342..f133a10d 100644 --- a/src/eu_proc.c +++ b/src/eu_proc.c @@ -31,6 +31,11 @@ static volatile long g_interval_count = 0; // 启动自动更新的时间间 static int on_proc_create_widgets(HWND hwnd) { + if (on_toolbar_create_dlg(hwnd)) + { + eu_logmsg("on_toolbar_create_dl return false\n"); + return 1; + } if (on_treebar_create_dlg(hwnd)) { eu_logmsg("on_treebar_create_dlg return false\n"); @@ -41,6 +46,11 @@ on_proc_create_widgets(HWND hwnd) eu_logmsg("on_tabpage_create_dlg return false\n"); return 1; } + if (on_statusbar_create_dlg(hwnd)) + { + eu_logmsg("on_statusbar_create_dlg return false\n"); + return 1; + } return SKYLARK_OK; } @@ -213,130 +223,51 @@ on_proc_move_sidebar(eu_tabpage *pnode) /***************************************************************************** * 主窗口缩放处理函数 - * 一次性处理所有窗口, 不在每个窗口处理WM_SIZE消息了 ******************************************************************************/ static void -on_proc_msg_size(HWND hwnd, eu_tabpage *ptab) +on_proc_msg_size(HWND hwnd, eu_tabpage *pnode) { - RECT rc = {0}; - RECT rect_treebar = {0}; - RECT rect_tabbar = {0}; - eu_tabpage *pnode = ptab ? ptab : on_tabpage_focus_at(); - if (pnode) + const bool redraw = pnode == NULL; + if (pnode || (pnode = on_tabpage_focus_at())) { - int number = 10; - on_toolbar_adjust_box(); - on_statusbar_adjust_box(); - on_tabpage_adjust_box(&rect_tabbar); - on_treebar_adjust_box(&rect_treebar); - on_tabpage_adjust_window(pnode); - GetWindowRect(hwnd ? hwnd : eu_module_hwnd(), &rc); - if (ptab) - { - number -= 5; - } - HDWP hdwp = BeginDeferWindowPos(number); - if (!ptab) + RECT rc_tabbar = {0}; + on_tabpage_adjust_window(pnode, &rc_tabbar); + if (pnode->hwnd_sc) { - if (eu_get_config()->m_toolbar != IDB_SIZE_0) + HDWP hdwp = NULL; + int number = 3; + if (pnode->hwnd_symlist || pnode->hwnd_symtree) { - DeferWindowPos(hdwp, on_toolbar_hwnd(), HWND_TOP, 0, 0, rc.right - rc.left, on_toolbar_height(), SWP_SHOWWINDOW); + ++number; } - else - { - DeferWindowPos(hdwp, on_toolbar_hwnd(), 0, 0, 0, 0, 0, SWP_HIDEWINDOW); - } - if (eu_get_config()->m_ftree_show) - { - RECT rect_filetree = {0}; - on_treebar_adjust_filetree(&rect_treebar, &rect_filetree); - DeferWindowPos(hdwp, - g_treebar, - HWND_TOP, - rect_treebar.left, - rect_treebar.top, - rect_treebar.right - rect_treebar.left, - rect_treebar.bottom - rect_treebar.top, - SWP_SHOWWINDOW); - DeferWindowPos(hdwp, - g_filetree, - HWND_TOP, - rect_filetree.left, - rect_filetree.top, - rect_filetree.right - rect_filetree.left, - rect_filetree.bottom - rect_filetree.top, - SWP_SHOWWINDOW); - DeferWindowPos(hdwp, - g_splitter_treebar, - HWND_TOP, - rect_treebar.right, - pnode->rect_sc.top, - SPLIT_WIDTH, - rect_treebar.bottom - pnode->rect_sc.top, - SWP_SHOWWINDOW); - } - else + if (document_map_initialized && hwnd_document_map) { - DeferWindowPos(hdwp, g_treebar, 0, 0, 0, 0, 0, SWP_HIDEWINDOW); - DeferWindowPos(hdwp, g_filetree, 0, 0, 0, 0, 0, SWP_HIDEWINDOW); - DeferWindowPos(hdwp, g_splitter_treebar, 0, 0, 0, 0, 0, SWP_HIDEWINDOW); + eu_setpos_window(hwnd_document_map, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); } - DeferWindowPos(hdwp, g_tabpages, HWND_TOP, rect_tabbar.left, rect_tabbar.top, - rect_tabbar.right - rect_tabbar.left, rect_tabbar.bottom - rect_tabbar.top, SWP_SHOWWINDOW); - } - if (pnode->hwnd_sc) - { - DeferWindowPos(hdwp, pnode->hwnd_sc, HWND_TOP, pnode->rect_sc.left, pnode->rect_sc.top, - pnode->rect_sc.right - pnode->rect_sc.left, pnode->rect_sc.bottom - pnode->rect_sc.top, SWP_SHOWWINDOW); + hdwp = BeginDeferWindowPos(number); // 先隐藏右边侧边栏 - DeferWindowPos(hdwp, g_splitter_symbar, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); + DeferWindowPos(hdwp,g_splitter_symbar, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); if (pnode->hwnd_symlist) { - DeferWindowPos(hdwp, pnode->hwnd_symlist, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); + DeferWindowPos(hdwp,pnode->hwnd_symlist, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); } else if (pnode->hwnd_symtree) { - DeferWindowPos(hdwp, pnode->hwnd_symtree, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); + DeferWindowPos(hdwp,pnode->hwnd_symtree, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); } - if (document_map_initialized && hwnd_document_map) - { - DeferWindowPos(hdwp, hwnd_document_map, 0, 0, 0, 0, 0, SWP_HIDEWINDOW); - } - } - if (eu_get_config()->m_statusbar) - { - if (g_statusbar) - { - DeferWindowPos(hdwp, g_statusbar, HWND_TOP, rc.left, rc.bottom - on_statusbar_height(), - rc.right - rc.left, on_statusbar_height(), SWP_SHOWWINDOW); - SendMessage(g_statusbar, WM_STATUS_REFRESH, 0, 0); - on_statusbar_btn_rw(pnode, true); - } - } - else if (g_statusbar) - { - DeferWindowPos(hdwp, g_statusbar, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); - } - if (true) - { + DeferWindowPos(hdwp,pnode->hwnd_sc, HWND_TOP, pnode->rect_sc.left, pnode->rect_sc.top, + pnode->rect_sc.right - pnode->rect_sc.left, pnode->rect_sc.bottom - pnode->rect_sc.top, SWP_SHOWWINDOW); + DeferWindowPos(hdwp,g_tabpages, HWND_TOP, rc_tabbar.left, rc_tabbar.top, + rc_tabbar.right - rc_tabbar.left, on_tabpage_get_height(), SWP_NOREDRAW); EndDeferWindowPos(hdwp); - if (!ptab) - { // 重新计算标签栏大小 - on_tabpage_adjust_box(&rect_tabbar); - on_tabpage_adjust_window(pnode); - eu_setpos_window(g_tabpages, HWND_TOP, rect_tabbar.left, rect_tabbar.top, - rect_tabbar.right - rect_tabbar.left, rect_tabbar.bottom - rect_tabbar.top, SWP_SHOWWINDOW); - eu_setpos_window(pnode->hwnd_sc, HWND_TOP, pnode->rect_sc.left, pnode->rect_sc.top, - pnode->rect_sc.right - pnode->rect_sc.left, pnode->rect_sc.bottom - pnode->rect_sc.top, SWP_SHOWWINDOW); + if (redraw) + { UpdateWindowEx(g_tabpages); - UpdateWindowEx(pnode->hwnd_sc); } + // tabbar调整位置后重绘工作区 + UpdateWindowEx(pnode->hwnd_sc); // 重新加上位置后显示 on_proc_move_sidebar(pnode); - if (g_splitter_treebar) - { - UpdateWindowEx(g_splitter_treebar); - } } for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { @@ -351,7 +282,7 @@ on_proc_msg_size(HWND hwnd, eu_tabpage *ptab) ShowWindow(p->hwnd_qrtable, SW_HIDE); } } - if (p->hex_mode && p->hwnd_sc) + if (p->hwnd_sc) { ShowWindow(p->hwnd_sc, SW_HIDE); } @@ -377,7 +308,9 @@ on_proc_msg_size(HWND hwnd, eu_tabpage *ptab) UpdateWindow(g_splitter_tablebar); } } - PostMessage(hwnd, WM_ACTIVATE, MAKEWPARAM(WA_CLICKACTIVE, 0), 0); + on_statusbar_size(pnode); + // 从插件页面切换时获取鼠标焦点 + on_proc_msg_active(pnode); } } @@ -387,7 +320,7 @@ on_proc_tab_click(HWND hwnd, eu_tabpage *pnode) on_proc_msg_size(hwnd, pnode); if (pnode && pnode->nc_pos >= 0 && eu_get_config() && eu_get_config()->scroll_to_cursor) { - if (pnode->hex_mode) + if (TAB_HEX_MODE(pnode)) { eu_sci_call(pnode, SCI_GOTOPOS, pnode->nc_pos, 0); } @@ -553,7 +486,8 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) TOOLTIPTEXT *p_tips = NULL; eu_tabpage *pnode = NULL; LRESULT result = 0; - if (eu_get_config()->m_menubar && eu_win10_or_later() != (uint32_t)-1 && on_theme_menu_proc(hwnd, message, wParam, lParam, &result)) + const bool menu_draw = eu_get_config()->m_menubar && eu_win10_or_later() != (uint32_t)-1 && !util_under_wine(); + if (menu_draw && on_theme_menu_proc(hwnd, message, wParam, lParam, &result)) { return result; } @@ -567,15 +501,29 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_NCLBUTTONDOWN: case WM_WINDOWPOSCHANGING: case WM_WINDOWPOSCHANGED: + { + return DefWindowProc(hwnd, message, wParam, lParam); + } + case WM_NCLBUTTONDBLCLK: + { // 防止标签栏被误拖动 + on_tabpage_variable_reset(); return DefWindowProc(hwnd, message, wParam, lParam); + } case WM_ERASEBKGND: + { if (!on_dark_enable()) { return DefWindowProc(hwnd, message, wParam, lParam); } return 1; + } case WM_CREATE: - if (on_proc_create_widgets(hwnd)) + { + if (!on_theme_setup_font(hwnd)) + { + PostQuitMessage(0); + } + if (on_proc_create_widgets(hwnd) != SKYLARK_OK) { PostQuitMessage(0); } @@ -600,49 +548,36 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } } break; + } case WM_NCPAINT: { RECT r = {0}; HDC hdc = NULL; LRESULT result = DefWindowProc(hwnd, WM_NCPAINT, wParam, lParam); - if (!on_dark_enable()) - { // 系统dark模式关闭时, 动态刷新主题 - const int i = eu_theme_index(); - if (i == THEME_BLACK) - { - if (on_dark_supports()) - { - eu_dark_theme_release(false); - on_proc_msg_size(hwnd, NULL); - } - } - else if (i == THEME_WHITE) - { - hdc = GetWindowDC(hwnd); - on_proc_menu_border(hwnd, &r); - FillRect(hdc, &r, (HBRUSH)on_dark_get_bgbrush()); - } - } - else + if ((hdc = GetWindowDC(hwnd))) { - hdc = GetWindowDC(hwnd); on_proc_menu_border(hwnd, &r); FillRect(hdc, &r, (HBRUSH)on_dark_get_bgbrush()); - } - if (hdc) - { ReleaseDC(hwnd, hdc); } return result; } case WM_NCACTIVATE: + { return 1; + } case WM_SIZE: + { if (wParam != SIZE_MINIMIZED) { + on_treebar_size(); + on_toolbar_size(); + on_tabpage_size(); on_proc_msg_size(hwnd, NULL); + on_statusbar_size(NULL); } break; + } case WM_RBUTTONDOWN: case WM_LBUTTONDBLCLK: { @@ -663,8 +598,10 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; } case WM_TAB_CLICK: + { on_proc_tab_click(hwnd, (void *)wParam); return 1; + } case WM_UPCHECK_STATUS: { if ((intptr_t)wParam < 0) @@ -690,6 +627,7 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) return 1; } case WM_TIMER: + { if (KEY_DOWN(VK_ESCAPE)) { if (on_qrgen_hwnd()) @@ -705,7 +643,7 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { ONCE_RUN(on_changes_window(hwnd)); } - if (eu_get_config()->upgrade.enable) + if (eu_get_config()->upgrade.enable && on_update_lookup()) { if (g_interval_count == EU_UPTIMES) { // 启动更新进程 @@ -723,27 +661,45 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) on_session_do(hwnd); } break; + } case WM_INITMENUPOPUP: - // 展开时, 显示菜单状态 + { // 展开时, 显示菜单状态 menu_update_item((HMENU)wParam, false); break; + } case WM_UNINITMENUPOPUP: - // 合拢时, 启用所有菜单项 + { // 合拢时, 启用所有菜单项 menu_update_item((HMENU)wParam, true); break; + } case WM_SKYLARK_DESC: + { return WM_SKYLARK_DESC; + } case WM_ABOUT_RE: + { on_search_regxp_error(); break; + } case WM_DPICHANGED: { + eu_logmsg("main window recv WM_DPICHANGED\n"); on_theme_setup_font(hwnd); + menu_bmp_destroy(); on_tabpage_foreach(hexview_update_theme); on_toolbar_refresh(hwnd); - on_statusbar_init(hwnd); - menu_bmp_destroy(); - SendMessage(g_treebar, WM_DPICHANGED, 0, 0); + if (g_tabpages) + { + SendMessage(g_tabpages, WM_DPICHANGED, 0, 0); + } + if (g_treebar) + { + SendMessage(g_treebar, WM_DPICHANGED, 0, 0); + } + if (g_statusbar) + { + SendMessage(g_statusbar, WM_DPICHANGED, 0, 0); + } break; } case WM_CTLCOLORLISTBOX: @@ -789,36 +745,84 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; } case WM_THEMECHANGED: + { if (on_dark_supports()) { - HWND snippet = NULL; - on_dark_allow_window(hwnd, on_dark_enable()); - on_dark_refresh_titlebar(hwnd); - on_dark_tips_theme(g_tabpages, TCM_GETTOOLTIPS); - on_tabpage_foreach(on_tabpage_theme_changed); - if (g_statusbar) + if (wParam == DARK_THEME_APPLY) { - on_statusbar_init(hwnd); + on_dark_allow_window(hwnd, true); + on_dark_refresh_titlebar(hwnd); + if (eu_win11_or_later()) + { + on_toolbar_refresh(hwnd); + } + else + { // win10 dark模式启动时刷新标题栏 + util_updateui_titlebar(hwnd); + } + SendMessage(g_statusbar, WM_THEMECHANGED, 0, 0); } - on_toolbar_refresh(hwnd); - on_dark_set_theme(g_treebar, L"Explorer", NULL); - if (g_filetree) + else { - SendMessage(g_filetree, WM_THEMECHANGED, 0, 0); + HWND snippet = NULL; + HWND htool = on_toolbar_hwnd(); + on_dark_allow_window(hwnd, on_dark_enable()); + on_dark_refresh_titlebar(hwnd); + if (g_tabpages) + { + on_dark_tips_theme(g_tabpages, TCM_GETTOOLTIPS); + on_tabpage_foreach(on_tabpage_theme_changed); + } + if (htool) + { + on_dark_tips_theme(htool, TB_GETTOOLTIPS); + SendMessage(htool, WM_THEMECHANGED, (WPARAM)hwnd, 0); + } + if (g_treebar) + { + SendMessage(g_treebar, WM_THEMECHANGED, 0, 0); + } + if (g_statusbar) + { + SendMessage(g_statusbar, WM_THEMECHANGED, 0, 0); + } + if ((snippet = eu_snippet_hwnd()) && IsWindowVisible(snippet)) + { + on_dark_set_theme(snippet, L"", L""); + on_dark_set_theme(snippet, L"Explorer", NULL); + } } - if ((snippet = eu_snippet_hwnd()) && IsWindowVisible(snippet)) + } + break; + } + case WM_SETTINGCHANGE: + { + if (on_dark_color_scheme_change(lParam) && eu_theme_index() == THEME_BLACK) + { + if (util_dark_theme()) { - on_dark_set_theme(snippet, L"", L""); - on_dark_set_theme(snippet, L"Explorer", NULL); + eu_logmsg("swiching dark mode\n"); + if (!on_dark_enable() && eu_dark_theme_init(true, true)) + { + SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_NORMAL, 10, 0); + on_view_refresh_theme(hwnd, true); + } + } + else if (!eu_win11_or_later()) + { + eu_logmsg("swiching light mode\n"); + eu_dark_theme_release(false); + on_proc_msg_size(hwnd, NULL); } } break; + } case WM_SYSCOMMAND: { if (wParam == SC_RESTORE) { const LRESULT rv = DefWindowProc(hwnd, message, wParam, lParam); - if ((pnode = on_tabpage_focus_at()) && !pnode->hex_mode && pnode->nc_pos >= 0) + if ((pnode = on_tabpage_focus_at()) && !TAB_HEX_MODE(pnode) && pnode->nc_pos >= 0) { eu_sci_call(pnode, SCI_SCROLLCARET, 0, 0); } @@ -863,24 +867,24 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } if (IDM_STYLETHEME_BASE <= wm_id && wm_id <= IDM_STYLETHEME_BASE + VIEW_STYLETHEME_MAXCOUNT - 1) { - on_view_switch_theme(g_hwndmain, wm_id); + on_view_switch_theme(hwnd, wm_id); break; } if (IDM_LOCALES_BASE <= wm_id && wm_id <= IDM_LOCALES_BASE + MAX_MULTI_LANG - 1) { - i18n_switch_locale(g_hwndmain, wm_id); + i18n_switch_locale(hwnd, wm_id); break; } if (IDM_SET_LUAJIT_EXECUTE <= wm_id && wm_id <= IDM_SET_LUAJIT_EXECUTE + DW_SIZE - 1) { eu_logmsg("Run custom menu, wm_id = %d\n", (int)wm_id); - on_setting_execute(g_hwndmain, wm_id); + on_setting_execute(hwnd, wm_id); break; } switch (wm_id) { case IDM_FILE_NEW: - on_file_new(); + on_file_new(NULL); break; case IDM_FILE_OPEN: on_file_open(); @@ -907,6 +911,9 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_FILE_CLOSEALL_EXCLUDE: on_file_exclude_close(pnode); break; + case IDM_FILE_UNMODIFIED: + on_file_unchange_close(pnode); + break; case IDM_FILE_RESTORE_RECENT: on_file_restore_recent(); break; @@ -1322,6 +1329,18 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_SEARCH_GOTO_NEXT_BOOKMARK_INALL: on_search_jmp_next_mark_all(pnode); break; + case IDM_EDIT_BOOKMARK_LINES_COPY: + on_edit_bookmark_copy(pnode); + break; + case IDM_EDIT_BOOKMARK_LINES_CUT: + on_edit_bookmark_cut(pnode); + break; + case IDM_EDIT_BOOKMARK_LINES_REMOVE: + on_edit_bookmark_remove(pnode); + break; + case IDM_EDIT_BOOKMARK_LINES_RESERVE: + on_edit_bookmark_reserve_remove(pnode); + break; case IDM_SEARCH_GOTOHOME: on_search_jmp_home(pnode); break; @@ -1375,7 +1394,7 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) on_view_light_fold(); break; case IDM_FORMAT_REFORMAT_JSON: - if (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_JSON) + if (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->doc_ptr->doc_type == DOCTYPE_JSON) { on_format_file_style(pnode); on_symtree_json(pnode); @@ -1383,7 +1402,7 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; case IDM_FORMAT_COMPRESS_JSON: - if (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_JSON) + if (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->doc_ptr->doc_type == DOCTYPE_JSON) { on_format_do_compress(pnode, on_format_json_callback); on_symtree_json(pnode); @@ -1391,7 +1410,7 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; case IDM_FORMAT_REFORMAT_JS: - if (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT) + if (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT) { on_format_file_style(pnode); on_symlist_reqular(pnode); @@ -1399,7 +1418,7 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; case IDM_FORMAT_COMPRESS_JS: - if (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT) + if (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT) { on_format_do_compress(pnode, on_format_js_callback); on_symlist_reqular(pnode); @@ -1407,7 +1426,7 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; case IDM_FORMAT_REFORMAT_XML: - if (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_XML) + if (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->doc_ptr->doc_type == DOCTYPE_XML) { on_format_file_style(pnode); on_xml_tree(pnode); @@ -1415,7 +1434,7 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; case IDM_FORMAT_COMPRESS_XML: - if (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_XML) + if (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->doc_ptr->doc_type == DOCTYPE_XML) { on_format_xml_compress(pnode); on_xml_tree(pnode); @@ -1423,21 +1442,39 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; case IDM_FORMAT_WHOLE_FILE: - on_format_clang_file(pnode, true); - on_sci_refresh_ui(pnode); + if (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && + (pnode->doc_ptr->doc_type == DOCTYPE_CPP || + pnode->doc_ptr->doc_type == DOCTYPE_CS || + pnode->doc_ptr->doc_type == DOCTYPE_VERILOG || + pnode->doc_ptr->doc_type == DOCTYPE_JAVA || + pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT || + pnode->doc_ptr->doc_type == DOCTYPE_JSON)) + { + on_format_clang_file(pnode, true); + on_sci_refresh_ui(pnode); + } break; case IDM_FORMAT_RANGLE_STR: - on_format_clang_file(pnode, false); - on_sci_refresh_ui(pnode); + if (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && + (pnode->doc_ptr->doc_type == DOCTYPE_CPP || + pnode->doc_ptr->doc_type == DOCTYPE_CS || + pnode->doc_ptr->doc_type == DOCTYPE_VERILOG || + pnode->doc_ptr->doc_type == DOCTYPE_JAVA || + pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT || + pnode->doc_ptr->doc_type == DOCTYPE_JSON)) + { + on_format_clang_file(pnode, false); + on_sci_refresh_ui(pnode); + } break; case IDM_FORMAT_RUN_SCRIPT: - if (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_LUA) + if (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->doc_ptr->doc_type == DOCTYPE_LUA) { on_toolbar_lua_exec(pnode); } break; case IDM_FORMAT_BYTE_CODE: - if (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_LUA) + if (pnode->doc_ptr && !TAB_HEX_MODE(pnode) && pnode->doc_ptr->doc_type == DOCTYPE_LUA) { do_byte_code(pnode); } @@ -1551,6 +1588,10 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_VIEW_SCROLLCURSOR: eu_get_config()->scroll_to_cursor ^= true; break; + case IDM_VIEW_TABBAR_SPLIT: + eu_get_config()->m_tab_split ^= true; + eu_window_resize(hwnd); + break; case IDM_VIEW_SWITCH_TAB: on_tabpage_switch_next(hwnd); break; @@ -1677,7 +1718,6 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { eu_get_config()->m_menubar ^= true; eu_get_config()->m_menubar?(GetMenu(hwnd)?(void)0:SetMenu(hwnd, i18n_load_menu(IDC_SKYLARK))):SetMenu(hwnd, NULL); - on_proc_msg_size(hwnd, NULL); break; } case IDB_SIZE_1: @@ -1694,9 +1734,11 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (eu_get_config()->m_toolbar != wm_id) { eu_get_config()->m_toolbar = wm_id; - g_toolbar_size = wm_id; + on_toolbar_icon_set(wm_id); if (on_toolbar_refresh(hwnd)) { + on_toolbar_size(); + on_treebar_size(); on_proc_msg_size(hwnd, NULL); } } @@ -1707,15 +1749,17 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (eu_get_config()->m_toolbar != IDB_SIZE_0) { - g_toolbar_size = eu_get_config()->m_toolbar; + on_toolbar_icon_set(eu_get_config()->m_toolbar); eu_get_config()->m_toolbar = IDB_SIZE_0; } else { - eu_get_config()->m_toolbar = g_toolbar_size ? g_toolbar_size : IDB_SIZE_1; + eu_get_config()->m_toolbar = on_toolbar_icon_get() ? on_toolbar_icon_get() : IDB_SIZE_1; } if (on_toolbar_refresh(hwnd)) { + on_toolbar_size(); + on_treebar_size(); on_proc_msg_size(hwnd, NULL); } break; @@ -1725,7 +1769,9 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (eu_get_config() && !(eu_get_config()->m_fullscreen)) { eu_get_config()->m_statusbar ^= true; + on_treebar_size(); on_proc_msg_size(hwnd, NULL); + on_statusbar_size(NULL); } break; } @@ -1773,7 +1819,8 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) switch (lpnmhdr->code) { case NM_CLICK: - if (!pnode->hex_mode && g_statusbar && lpnmhdr->hwndFrom == g_statusbar) + { + if (!TAB_HEX_MODE(pnode) && !TAB_HAS_PDF(pnode) && g_statusbar && lpnmhdr->hwndFrom == g_statusbar) { POINT pt; LPNMMOUSE lpnmm = (LPNMMOUSE)lParam; @@ -1781,13 +1828,14 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) on_statusbar_pop_menu((int)lpnmm->dwItemSpec, &pt); } break; + } case NM_CUSTOMDRAW: { if (eu_get_config() && eu_get_config()->m_toolbar && GetDlgItem(hwnd, IDC_TOOLBAR) == lpnmhdr->hwndFrom) { LPNMTBCUSTOMDRAW lptoolbar = (LPNMTBCUSTOMDRAW)lParam; if (lptoolbar) - { + { // 绘制toolbar FillRect(lptoolbar->nmcd.hdc, &lptoolbar->nmcd.rc, (HBRUSH)on_dark_get_bgbrush()); } } @@ -1923,13 +1971,13 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if ((lpnotify->updated)) { - if (pnode && (!(pnode->hex_mode || pnode->plugin))) + if (pnode && (!(TAB_HEX_MODE(pnode) || pnode->plugin))) { on_hyper_update_style(pnode); } if (lpnotify->updated & SC_UPDATE_SELECTION) { - if (eu_get_config()->m_light_str || KEY_DOWN(VK_SHIFT)) + if (pnode->raw_size < BUFF_32M && (eu_get_config()->m_light_str || KEY_DOWN(VK_SHIFT))) { on_view_editor_selection(pnode); } @@ -2045,19 +2093,18 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (LOWORD(wParam) != WA_INACTIVE && (pnode = on_tabpage_focus_at())) { - if (pnode->hwnd_sc && GetWindowLongPtr(pnode->hwnd_sc, GWL_STYLE) & WS_VISIBLE) - { - SetFocus(pnode->hwnd_sc); - } + on_proc_msg_active(pnode); } break; } case WM_DROPFILES: + { if (wParam) { on_file_drop((HDROP) wParam); } break; + } case WM_MOVE: { HWND hwnd_clip = on_toolbar_clip_hwnd(); @@ -2069,32 +2116,34 @@ on_proc_main_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { PostMessage(hwnd_document_map, WM_MOVE, 0, 0); } - if (g_statusbar) - { - PostMessage(g_statusbar, WM_MOVE, 0, 0); - } break; } case WM_CLOSE: + { if (hwnd == g_hwndmain) { on_file_edit_exit(hwnd); } break; + } case WM_BACKUP_OVER: + { if (hwnd == g_hwndmain) { DestroyWindow(hwnd); } break; + } case WM_DESTROY: - { - on_proc_destory_window(hwnd); - eu_logmsg("main window WM_DESTROY\n"); - break; - } + { + on_proc_destory_window(hwnd); + eu_logmsg("main window WM_DESTROY\n"); + break; + } default: + { return DefWindowProc(hwnd, message, wParam, lParam); + } } return 0; } @@ -2116,6 +2165,22 @@ on_proc_class_register(HINSTANCE instance) return RegisterClassEx(&wcex); } +void +on_proc_msg_active(eu_tabpage *pnode) +{ + if (pnode) + { + if (pnode->hwnd_sc && GetWindowLongPtr(pnode->hwnd_sc, GWL_STYLE) & WS_VISIBLE) + { + SetFocus(pnode->hwnd_sc); + } + if (eu_get_config()->m_statusbar && g_statusbar) + { + on_statusbar_update(pnode); + } + } +} + void on_proc_sync_wait(void) { // 销毁定时器 @@ -2128,12 +2193,6 @@ on_proc_sync_wait(void) on_session_thread_wait(); } -void -on_proc_resize(HWND hwnd) -{ // 当在线程需要刷新界面时, 使用消息让主线程刷新 - SendMessage(hwnd ? hwnd : eu_module_hwnd(), WM_SIZE, 0, 0); -} - void on_proc_counter_stop(void) { @@ -2206,8 +2265,8 @@ eu_dpi_scale_font(void) int eu_dpi_scale_style(int value, const int scale, const int min_value) { - value = (scale == USER_DEFAULT_SCREEN_DPI*100) ? value : MulDiv(value, scale, USER_DEFAULT_SCREEN_DPI*100); - return MAX(value, min_value); + value = (scale == USER_DEFAULT_SCREEN_DPI*100) ? value : MulDiv(value, scale, USER_DEFAULT_SCREEN_DPI*100); + return MAX(value, min_value); } int @@ -2221,18 +2280,6 @@ eu_dpi_scale_xy(int adpi, int m) return m; } -bool -eu_create_toolbar(HWND hwnd) -{ - return (on_toolbar_create(hwnd) == 0); -} - -bool -eu_create_statusbar(HWND hwnd) -{ - return on_statusbar_init(hwnd); -} - void eu_create_fullscreen(HWND hwnd) { @@ -2258,7 +2305,7 @@ eu_before_proc(MSG *p_msg) on_tabpage_active_one((int) (p_msg->wParam) - 0x31); return 1; } - if((pnode = on_tabpage_focus_at()) && pnode && pnode->doc_ptr && !pnode->hex_mode && p_msg->message == WM_KEYDOWN && p_msg->hwnd == pnode->hwnd_sc) + if((pnode = on_tabpage_focus_at()) && pnode && pnode->doc_ptr && !TAB_HEX_MODE(pnode) && p_msg->message == WM_KEYDOWN && p_msg->hwnd == pnode->hwnd_sc) { bool main_up = KEY_UP(VK_CONTROL) && KEY_UP(VK_MENU) && KEY_UP(VK_INSERT); bool main_down = KEY_DOWN(VK_CONTROL) && KEY_DOWN(VK_MENU) && KEY_DOWN(VK_INSERT) && KEY_DOWN(VK_SHIFT); @@ -2305,7 +2352,6 @@ eu_create_main_window(HINSTANCE instance) { LOAD_APP_RESSTR(IDS_APP_TITLE, app_title); g_hwndmain = CreateWindowEx(WS_EX_ACCEPTFILES, APP_CLASS, app_title, ac_flags, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, instance, NULL); - on_theme_setup_font(g_hwndmain); } } return g_hwndmain; diff --git a/src/eu_proc.h b/src/eu_proc.h index d47651a2..e0b7201a 100644 --- a/src/eu_proc.h +++ b/src/eu_proc.h @@ -30,8 +30,8 @@ extern "C" #endif void on_proc_counter_stop(void); -void on_proc_resize(HWND hwnd); void on_proc_sync_wait(void); +void on_proc_msg_active(eu_tabpage *pnode); void eu_window_resize(HWND hwnd); void eu_window_layout_dpi(HWND hwnd, const RECT *pnew_rect, const uint32_t adpi); HWND eu_hwnd_self(void); diff --git a/src/eu_scintilla.c b/src/eu_scintilla.c index 3262ac57..41c37d9f 100644 --- a/src/eu_scintilla.c +++ b/src/eu_scintilla.c @@ -22,8 +22,6 @@ volatile sptr_t eu_edit_wnd = 0; static volatile sptr_t ptr_scintilla = 0; -static volatile sptr_t last_sci_eusc = 0; -static volatile sptr_t last_sci_hwnd = 0; static const char *auto_xpm[] = { /* columns rows colors chars-per-pixel */ @@ -224,10 +222,10 @@ on_sci_init_default(eu_tabpage *pnode, const uint32_t bgcolor) // 代码折叠栏亮量颜色与填充色 eu_sci_call(pnode, SCI_SETFOLDMARGINCOLOUR, true, eu_get_theme()->item.foldmargin.bgcolor); eu_sci_call(pnode, SCI_SETFOLDMARGINHICOLOUR, true, eu_get_theme()->item.foldmargin.bgcolor); - eu_sci_call(pnode, SCI_MARKERSETFORETRANSLUCENT, SC_MARKNUM_FOLDER, eu_get_theme()->item.foldmargin.color); - eu_sci_call(pnode, SCI_MARKERSETFORETRANSLUCENT, SC_MARKNUM_FOLDEREND, eu_get_theme()->item.foldmargin.color); - eu_sci_call(pnode, SCI_MARKERSETFORETRANSLUCENT, SC_MARKNUM_FOLDEROPEN, eu_get_theme()->item.foldmargin.color); - eu_sci_call(pnode, SCI_MARKERSETFORETRANSLUCENT, SC_MARKNUM_FOLDEROPENMID, eu_get_theme()->item.foldmargin.color); + eu_sci_call(pnode, SCI_MARKERSETFORETRANSLUCENT, SC_MARKNUM_FOLDER, eu_get_theme()->item.foldmargin.color); + eu_sci_call(pnode, SCI_MARKERSETFORETRANSLUCENT, SC_MARKNUM_FOLDEREND, eu_get_theme()->item.foldmargin.color); + eu_sci_call(pnode, SCI_MARKERSETFORETRANSLUCENT, SC_MARKNUM_FOLDEROPEN, eu_get_theme()->item.foldmargin.color); + eu_sci_call(pnode, SCI_MARKERSETFORETRANSLUCENT, SC_MARKNUM_FOLDEROPENMID, eu_get_theme()->item.foldmargin.color); // 是否自动换行 eu_sci_call(pnode, SCI_SETWRAPMODE, (eu_get_config()->line_mode ? SC_WRAP_CHAR : SC_WRAP_NONE), 0); // 换行符样式 @@ -305,6 +303,15 @@ on_sci_reset_zoom(eu_tabpage *pnode) } } +static inline void +on_sci_update_size(eu_tabpage *pnode) +{ + if (pnode) + { + pnode->raw_size = eu_sci_call(pnode, SCI_GETLENGTH, 0, 0) + pnode->pre_len; + } +} + void on_sci_before_file(eu_tabpage *pnode, const bool init) { @@ -326,7 +333,7 @@ on_sci_after_file(eu_tabpage *pnode, const bool init) { if (pnode) { - if (!pnode->hex_mode && !pnode->pmod) + if (!TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_SETEOLMODE, pnode->eol, 0); if (init) @@ -338,7 +345,7 @@ on_sci_after_file(eu_tabpage *pnode, const bool init) on_sci_reset_zoom(pnode); if (!pnode->raw_size) { - pnode->raw_size = eu_sci_call(pnode, SCI_GETLENGTH, 0, 0) + pnode->pre_len; + on_sci_update_size(pnode); } if (pnode->doc_ptr && pnode->doc_ptr->fn_init_after) { // 设置此标签页的语法解析 @@ -359,9 +366,10 @@ on_sci_refresh_ui(eu_tabpage *pnode) if (pnode) { on_toolbar_update_button(); - on_statusbar_update(); + on_statusbar_update(pnode); on_sci_update_line_margin(pnode); on_sci_update_fold_margin(pnode); + on_sci_update_size(pnode); util_redraw(g_tabpages, true); } } @@ -407,21 +415,11 @@ on_sci_delete_file(const eu_tabpage *pnode) } static void -on_sci_swap_hwnd(eu_tabpage *pnode) +on_sci_destroy_hwnd(eu_tabpage *pnode) { - if (pnode) + if (pnode && pnode->hwnd_sc) { - if (!pnode->phex && !pnode->pmod && TabCtrl_GetItemCount(g_tabpages) <= 0 && pnode->hwnd_sc && pnode->eusc) - { // 最后一个标签时, 保存scintilla窗口句柄 - inter_atom_exchange(&last_sci_hwnd, (sptr_t)pnode->hwnd_sc); - inter_atom_exchange(&last_sci_eusc, (sptr_t)pnode->eusc); - } - else if (pnode->hwnd_sc) - { // 销毁scintilla窗口 - SendMessage(pnode->hwnd_sc, WM_CLOSE, 0, 0); - inter_atom_exchange(&last_sci_hwnd, 0); - inter_atom_exchange(&last_sci_eusc, 0); - } + SendMessage(pnode->hwnd_sc, WM_CLOSE, 0, 0); } } @@ -477,9 +475,17 @@ on_sci_destroy_control(eu_tabpage *pnode) cvector_freep(&pnode->re_group); } // 关闭minimap窗口 - if (!on_tabpage_check_map() && hwnd_document_map) + if (!on_tabpage_exist_map()) { - DestroyWindow(hwnd_document_map); + if (hwnd_document_map) + { + DestroyWindow(hwnd_document_map); + pnode->map_show = false; + } + } + else if (pnode->map_show && hwnd_document_map) + { + eu_setpos_window(hwnd_document_map, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); pnode->map_show = false; } } @@ -490,6 +496,7 @@ on_sci_free_tab(eu_tabpage **ppnode) { if (STR_NOT_NUL(ppnode)) { + int reason = (*ppnode)->reason; util_lock(&(*ppnode)->busy_id); // 销毁子窗口资源 on_sci_destroy_control(*ppnode); @@ -499,8 +506,11 @@ on_sci_free_tab(eu_tabpage **ppnode) np_plugins_destroy(&(*ppnode)->plugin->funcs, &(*ppnode)->plugin->npp, NULL); np_plugins_shutdown(&(*ppnode)->pmod, &(*ppnode)->plugin); } - // 切换16进制时,销毁相关资源 - on_sci_swap_hwnd(*ppnode); + // 销毁编辑器窗口 + if (reason != TABS_MAYBE_RESERVE) + { + on_sci_destroy_hwnd(*ppnode); + } // 关闭可能加载的动态库 eu_close_dll((*ppnode)->pmod); // 清理缓存文件 @@ -508,8 +518,22 @@ on_sci_free_tab(eu_tabpage **ppnode) // 清除标签单次运行锁状态 _InterlockedExchange(&(*ppnode)->lock_id, 0); util_unlock(&(*ppnode)->busy_id); - eu_safe_free(*ppnode); - eu_logmsg("%s: we free the node's memory\n", __FUNCTION__); + if (reason != TABS_MAYBE_RESERVE) + { + eu_safe_free(*ppnode); + eu_logmsg("%s: we free the node's memory\n", __FUNCTION__); + } + else + { + (*ppnode)->reason = 0; + on_file_new(*ppnode); + eu_logmsg("%s: on_file_new() execute\n", __FUNCTION__); + } + if (reason == TABS_MAYBE_EIXT && on_sql_sync_session() == SKYLARK_OK) + { + eu_logmsg("close last tab, skylark exit ...\n"); + SendMessage(eu_module_hwnd(), WM_BACKUP_OVER, 0, 0); + } } } @@ -603,7 +627,7 @@ on_sci_point_left(eu_tabpage *pnode) void on_sci_character(eu_tabpage *pnode, ptr_notify lpnotify) { - if (pnode && !pnode->hex_mode && pnode->doc_ptr && pnode->doc_ptr->fn_on_char) + if (pnode && !TAB_HEX_MODE(pnode) && pnode->doc_ptr && pnode->doc_ptr->fn_on_char) { pnode->doc_ptr->fn_on_char(pnode, lpnotify); } @@ -628,7 +652,7 @@ on_sci_update_line_margin(eu_tabpage *pnode) void on_sci_update_fold_margin(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->plugin) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->plugin) { const int zoom = (const int) eu_sci_call(pnode, SCI_GETZOOM, 0, 0); const int scalex = eu_get_dpi(eu_hwnd_self()) * zoom; @@ -910,12 +934,6 @@ sc_edit_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; } - case WM_SETFOCUS: - { - NMHDR nm = {0}; - eu_send_notify(hwnd, NM_SETFOCUS, &nm); - break; - } case WM_DESTROY: { eu_logmsg("scintilla WM_DESTROY\n"); @@ -965,19 +983,11 @@ on_sci_create(eu_tabpage *pnode, HWND parent, int flags, WNDPROC sc_callback) int on_sci_init_dlg(eu_tabpage *pnode) { - if (!pnode) - { - return EUE_POINT_NULL; - } - if (last_sci_hwnd) + if (pnode) { - pnode->hwnd_sc = (HWND)last_sci_hwnd; - pnode->eusc = last_sci_eusc; - inter_atom_exchange(&last_sci_hwnd, 0); - inter_atom_exchange(&last_sci_eusc, 0); - return SKYLARK_OK; + return on_sci_create(pnode, NULL, !TAB_HEX_MODE(pnode) && pnode->pmod ? WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_EX_RTLREADING : 0, NULL); } - return on_sci_create(pnode, NULL, !pnode->hex_mode && pnode->pmod ? WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_EX_RTLREADING : 0, NULL); + return EUE_POINT_NULL; } void @@ -998,7 +1008,7 @@ sptr_t eu_sci_call(eu_tabpage *p, int m, sptr_t w, sptr_t l) { return ((p && p->hwnd_sc) ? - (p->hex_mode ? SendMessage(p->hwnd_sc, m, w, l) : + (TAB_HEX_MODE(p) ? SendMessage(p->hwnd_sc, m, w, l) : (ptr_scintilla && p->eusc) ? ((SciFnDirect)ptr_scintilla)(p->eusc, m, w, l) : 0) : 0); } diff --git a/src/eu_script.c b/src/eu_script.c index 484298e4..d89ca9de 100644 --- a/src/eu_script.c +++ b/src/eu_script.c @@ -671,7 +671,7 @@ do_lua_func(const char *fname, const char *func, const char *arg) } else { - eu_logmsg("%s: lua_pcall failed\n", __FUNCTION__); + eu_logmsg("%s: %s:%s lua_pcall failed\n", __FUNCTION__, fname, func); } } lua_close(L); @@ -946,7 +946,7 @@ do_byte_code(eu_tabpage *pnode) } allclean: pnode->presult->pwant = on_toolbar_no_highlight; - on_proc_resize(NULL); + eu_window_resize(NULL); if (!status) { char u8_path[MAX_BUFFER] = {0}; diff --git a/src/eu_search.c b/src/eu_search.c index be7ab6e6..6bedbd66 100644 --- a/src/eu_search.c +++ b/src/eu_search.c @@ -18,7 +18,6 @@ #include "framework.h" #include -#define LINE_NOT_FOUND ((sptr_t)-1) #define MAX_TRACE_COUNT 8192 #define RESULAT_MAX_MATCH (UINT16_MAX * 2 + 1) #define INVISIBLE_BITMASK() on_sci_bitmask_get(0, 1) @@ -166,7 +165,7 @@ on_search_tab_ui(int index) hc = GetDlgItem(hwnd_search_dlg, IDC_WHAT_FOLDER_CBO); EnableWindow(hc, true); hc = GetDlgItem(hwnd_search_dlg, IDC_MATCH_CASE); - if (!pnode->hex_mode) + if (!TAB_HEX_MODE(pnode)) { EnableWindow(hc, true); CONTROL_HANDLE(hc, IDC_MATCH_ALL_FILE, SW_SHOW) @@ -237,24 +236,24 @@ on_search_tab_ui(int index) CONTROL_HANDLE(hc, IDC_SEARCH_ALL_BTN, SW_HIDE) CONTROL_HANDLE(hc, IDC_SEARCH_HEX_STRINGS, SW_HIDE) CONTROL_HANDLE(hc, IDC_SEARCH_HEX_STC, SW_HIDE) - CONTROL_HANDLE(hc, IDC_MATCH_ALL_FILE, !pnode->hex_mode ? SW_SHOW : SW_HIDE) - CONTROL_HANDLE(hc, IDC_MATCH_LOOP, !pnode->hex_mode ? SW_SHOW : SW_HIDE) - CONTROL_HANDLE(hc, IDC_MATCH_WDSTART, !pnode->hex_mode ? SW_SHOW : SW_HIDE) - CONTROL_HANDLE(hc, IDC_MATCH_WORD, !pnode->hex_mode ? SW_SHOW : SW_HIDE) + CONTROL_HANDLE(hc, IDC_MATCH_ALL_FILE, !TAB_HEX_MODE(pnode) ? SW_SHOW : SW_HIDE) + CONTROL_HANDLE(hc, IDC_MATCH_LOOP, !TAB_HEX_MODE(pnode) ? SW_SHOW : SW_HIDE) + CONTROL_HANDLE(hc, IDC_MATCH_WDSTART, !TAB_HEX_MODE(pnode) ? SW_SHOW : SW_HIDE) + CONTROL_HANDLE(hc, IDC_MATCH_WORD, !TAB_HEX_MODE(pnode) ? SW_SHOW : SW_HIDE) hc = GetDlgItem(hwnd_search_dlg, IDC_MATCH_CASE); EnableWindow(hc, true); hc = GetDlgItem(hwnd_search_dlg, IDC_MODE_REGEXP); EnableWindow(hc, true); - CONTROL_HANDLE(hc, IDC_SEARCH_PRE_BTN, !pnode->hex_mode ? SW_SHOW : SW_HIDE) - CONTROL_HANDLE(hc, IDC_SEARCH_NEXT_BTN, !pnode->hex_mode ? SW_SHOW : SW_HIDE) + CONTROL_HANDLE(hc, IDC_SEARCH_PRE_BTN, !TAB_HEX_MODE(pnode) ? SW_SHOW : SW_HIDE) + CONTROL_HANDLE(hc, IDC_SEARCH_NEXT_BTN, !TAB_HEX_MODE(pnode) ? SW_SHOW : SW_HIDE) GetWindowRect(hc, &rc); MapWindowPoints(NULL, hwnd_search_dlg, (LPPOINT)&rc, 2); - CONTROL_HANDLE(hc, IDC_SEARCH_RE_BTN, !pnode->hex_mode ? SW_SHOW : SW_HIDE) + CONTROL_HANDLE(hc, IDC_SEARCH_RE_BTN, !TAB_HEX_MODE(pnode) ? SW_SHOW : SW_HIDE) MoveWindow(hc, rc.left, rc.bottom + 4, rc.right - rc.left, rc.bottom - rc.top, TRUE); - CONTROL_HANDLE(hc, IDC_SEARCH_REALL_BTN, !pnode->hex_mode ? SW_SHOW : SW_HIDE) + CONTROL_HANDLE(hc, IDC_SEARCH_REALL_BTN, !TAB_HEX_MODE(pnode) ? SW_SHOW : SW_HIDE) MoveWindow(hc, rc.left, rc.bottom + (rc.bottom - rc.top) + 6, rc.right - rc.left, rc.bottom - rc.top, TRUE); hc = GetDlgItem(hwnd_search_dlg, IDC_WHAT_FOLDER_CBO); - if (pnode->hex_mode) + if (TAB_HEX_MODE(pnode)) { EnableWindow(hc, false); CONTROL_HANDLE(hc, IDC_SEARCH_SELRE_BTN, SW_HIDE) @@ -267,8 +266,8 @@ on_search_tab_ui(int index) util_can_selections(pnode) ? EnableWindow(hc, true) : EnableWindow(hc, false); } - CONTROL_HANDLE(hc, IDC_SEARCH_RP_CBO, !pnode->hex_mode ? SW_SHOW : SW_HIDE) - pnode->hex_mode ? EnableWindow(hc, false) : EnableWindow(hc, true); + CONTROL_HANDLE(hc, IDC_SEARCH_RP_CBO, !TAB_HEX_MODE(pnode) ? SW_SHOW : SW_HIDE) + TAB_HEX_MODE(pnode) ? EnableWindow(hc, false) : EnableWindow(hc, true); CONTROL_HANDLE(hc, IDC_SEARCH_CLOSE_BTN, SW_SHOW) LOAD_I18N_RESSTR(IDC_MSG_SEARCH_TIT2, tit_str); SetWindowText(hwnd_search_dlg, tit_str); @@ -415,7 +414,7 @@ on_search_jmp_pos(eu_tabpage *pnode) { if (pnode) { - if (!pnode->nc_pos || pnode->hex_mode) + if (!pnode->nc_pos || TAB_HEX_MODE(pnode)) { eu_sci_call(pnode, SCI_GOTOPOS, pnode->nc_pos, 0); } @@ -431,7 +430,7 @@ on_search_jmp_pos(eu_tabpage *pnode) void on_search_jmp_matching_brace(eu_tabpage *pnode, int *pres) { - if (pnode && pres && !pnode->hex_mode && !pnode->plugin) + if (pnode && pres && !TAB_HEX_MODE(pnode) && !pnode->plugin) { int char_before = 0; sptr_t brace_caret = -1; @@ -598,7 +597,7 @@ on_search_set_folder_path(LPCTSTR path) void on_search_turn_select(eu_tabpage *pnode) { - if (hwnd_search_dlg && pnode && !pnode->hex_mode) + if (hwnd_search_dlg && pnode && !TAB_HEX_MODE(pnode)) { HWND hwnd_tab = GetDlgItem(hwnd_search_dlg, IDD_SEARCH_TAB_1); if (hwnd_tab && TabCtrl_GetCurSel(hwnd_tab) == 1) @@ -665,7 +664,7 @@ on_search_find_next(eu_tabpage *pnode) int on_search_replace_thread(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { HWND hwnd_what = GetDlgItem(hwnd_search_dlg, IDC_WHAT_FOLDER_CBO); HWND hwnd_tab = GetDlgItem(hwnd_search_dlg, IDD_SEARCH_TAB_1); @@ -721,7 +720,7 @@ on_search_file_thread(const TCHAR *path) void on_search_set_selection(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { if (pnode->begin_pos == -1) { @@ -738,7 +737,7 @@ on_search_set_selection(eu_tabpage *pnode) void on_search_set_rectangle(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { if (eu_sci_call(pnode, SCI_GETSELECTIONMODE, 0, 0) == SC_SEL_STREAM) { @@ -761,7 +760,7 @@ on_search_set_rectangle(eu_tabpage *pnode) void on_search_select_all(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_SELECTALL, 0, 0); } @@ -770,7 +769,7 @@ on_search_select_all(eu_tabpage *pnode) void on_search_select_word(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { sptr_t pos = eu_sci_call(pnode, SCI_GETCURRENTPOS, 0, 0); sptr_t wd_start = eu_sci_call(pnode, SCI_WORDSTARTPOSITION, pos, true); @@ -782,7 +781,7 @@ on_search_select_word(eu_tabpage *pnode) void on_search_select_line(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { // 支持类似visual studio的单行操作 // TAB键增加缩进, Shift+TAB减少缩进 @@ -793,7 +792,7 @@ on_search_select_line(eu_tabpage *pnode) void on_search_select_se(eu_tabpage *pnode, uint16_t id) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { sptr_t sel_start = 0; sptr_t sel_end = 0; @@ -815,7 +814,7 @@ on_search_select_se(eu_tabpage *pnode, uint16_t id) void on_search_select_left_word(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_WORDPARTLEFTEXTEND, 0, 0); } @@ -824,7 +823,7 @@ on_search_select_left_word(eu_tabpage *pnode) void on_search_select_right_word(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_WORDPARTRIGHTEXTEND, 0, 0); } @@ -833,7 +832,7 @@ on_search_select_right_word(eu_tabpage *pnode) void on_search_select_left_group(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_WORDLEFTEXTEND, 0, 0); } @@ -842,7 +841,7 @@ on_search_select_left_group(eu_tabpage *pnode) void on_search_select_right_group(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_WORDRIGHTEXTEND, 0, 0); } @@ -851,7 +850,7 @@ on_search_select_right_group(eu_tabpage *pnode) void on_search_cumulative_previous_block(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_PARAUPEXTEND, 0, 0); } @@ -860,7 +859,7 @@ on_search_cumulative_previous_block(eu_tabpage *pnode) void on_search_cumulative_next_block(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_PARADOWNEXTEND, 0, 0); } @@ -869,7 +868,7 @@ on_search_cumulative_next_block(eu_tabpage *pnode) void on_search_move_to_lgroup(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_WORDPARTLEFT, 0, 0); } @@ -878,7 +877,7 @@ on_search_move_to_lgroup(eu_tabpage *pnode) void on_search_move_to_rgroup(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_WORDPARTRIGHT, 0, 0); } @@ -887,7 +886,7 @@ on_search_move_to_rgroup(eu_tabpage *pnode) void on_search_move_to_lword(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_WORDLEFT, 0, 0); } @@ -896,7 +895,7 @@ on_search_move_to_lword(eu_tabpage *pnode) void on_search_move_to_rword(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_WORDRIGHT, 0, 0); } @@ -905,7 +904,7 @@ on_search_move_to_rword(eu_tabpage *pnode) void on_search_move_to_top_block(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_PARAUP, 0, 0); } @@ -914,7 +913,7 @@ on_search_move_to_top_block(eu_tabpage *pnode) void on_search_move_to_bottom_block(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { eu_sci_call(pnode, SCI_PARADOWN, 0, 0); } @@ -925,7 +924,7 @@ on_search_jmp_home(eu_tabpage *pnode) { if (pnode && !pnode->pmod) { - if (pnode->hex_mode) + if (TAB_HEX_MODE(pnode)) { SendMessage(pnode->hwnd_sc, WM_KEYDOWN, VK_HOME, 0); } @@ -946,7 +945,7 @@ on_search_jmp_end(eu_tabpage *pnode) { if (pnode && !pnode->pmod) { - if (pnode->hex_mode) + if (TAB_HEX_MODE(pnode)) { SendMessage(pnode->hwnd_sc, WM_KEYDOWN, VK_END, 0); } @@ -971,7 +970,7 @@ on_search_jmp_specified_line(eu_tabpage *pnode) TCHAR tip_str[MAX_LOADSTRING] = {0}; if (pnode && !pnode->pmod) { - if (pnode->hex_mode) + if (TAB_HEX_MODE(pnode)) { eu_i18n_load_str(IDC_MSG_SEARCH_STR5, tip_str, 0); } @@ -981,7 +980,7 @@ on_search_jmp_specified_line(eu_tabpage *pnode) } if (eu_input(tip_str, lineno, _countof(lineno))) { - if (pnode->hex_mode) + if (TAB_HEX_MODE(pnode)) { if (_stscanf(lineno, _T("%zx"), &line) == 1) @@ -1004,7 +1003,7 @@ on_search_jmp_specified_line(eu_tabpage *pnode) void on_search_toggle_mark(eu_tabpage *pnode, sptr_t lineno) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { int bitmask = 0; bool bookmark = false; @@ -1041,7 +1040,7 @@ static void on_search_add_mark(eu_tabpage *pnode, sptr_t lineno) { sptr_t current_line = lineno; - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { if (current_line < 0) { @@ -1055,7 +1054,7 @@ on_search_add_mark(eu_tabpage *pnode, sptr_t lineno) static void on_search_remove_marks_this(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { sptr_t pos = eu_sci_call(pnode, SCI_GETCURRENTPOS, 0, 0); sptr_t current_line = eu_sci_call(pnode, SCI_LINEFROMPOSITION, pos, 0); @@ -1069,19 +1068,22 @@ on_search_remove_marks_all(eu_tabpage *pnode) eu_tabpage *p = NULL; for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { - if ((p = on_tabpage_get_ptr(index)) && !p->hex_mode && !p->pmod) + if ((p = on_tabpage_get_ptr(index)) && !TAB_HEX_MODE(p) && !p->pmod) { eu_sci_call(p, SCI_MARKERDELETEALL, MARGIN_BOOKMARK_VALUE, 0); } } } -static inline sptr_t -on_search_mrker_next(eu_tabpage *pnode, const sptr_t line, const int bitmask) +sptr_t +on_search_marker_next(eu_tabpage *pnode, const sptr_t line, sptr_t last, const int bitmask) { if (bitmask & CHANGE_HISTORY_BITMASK()) { - const sptr_t last = eu_sci_call(pnode, SCI_GETLINECOUNT, 0, 0); + if (last <= 0) + { + last = eu_sci_call(pnode, SCI_GETLINECOUNT, 0, 0); + } for (sptr_t i = line; i <= last; ++i) { if (eu_sci_call(pnode, SCI_MARKERGET, i, 0) & bitmask) @@ -1114,7 +1116,7 @@ on_search_marker_previous(eu_tabpage *pnode, const sptr_t line, const int bitmas void on_search_jmp_premark_this(eu_tabpage *pnode, const int mask) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { sptr_t pos = eu_sci_call(pnode, SCI_GETCURRENTPOS, 0, 0); sptr_t current_line = eu_sci_call(pnode, SCI_LINEFROMPOSITION, pos, 0); @@ -1129,11 +1131,11 @@ on_search_jmp_premark_this(eu_tabpage *pnode, const int mask) void on_search_jmp_next_mark_this(eu_tabpage *pnode, const int mask) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { sptr_t pos = eu_sci_call(pnode, SCI_GETCURRENTPOS, 0, 0); sptr_t current_line = eu_sci_call(pnode, SCI_LINEFROMPOSITION, pos, 0); - sptr_t find_line = on_search_mrker_next(pnode, current_line + 1, mask); + sptr_t find_line = on_search_marker_next(pnode, current_line + 1, -1, mask); if (find_line != LINE_NOT_FOUND) { on_search_jmp_line(pnode, find_line, current_line); @@ -1144,7 +1146,7 @@ on_search_jmp_next_mark_this(eu_tabpage *pnode, const int mask) void on_search_jmp_previous_history(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { const int maskn = eu_get_config()->history_mask - IDM_VIEW_HISTORY_PLACEHOLDE; if (maskn > 1) @@ -1166,7 +1168,7 @@ on_search_jmp_previous_history(eu_tabpage *pnode) void on_search_jmp_next_history(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { const int maskn = eu_get_config()->history_mask - IDM_VIEW_HISTORY_PLACEHOLDE; if (maskn > 1) @@ -1251,7 +1253,7 @@ on_search_jmp_next_mark_all(eu_tabpage *pnode) { for (index++; index < count; index++) { - if ((p = on_tabpage_get_ptr(index)) && !p->hex_mode && !p->pmod) + if ((p = on_tabpage_get_ptr(index)) && !TAB_HEX_MODE(p) && !p->pmod) { find_line = eu_sci_call(p, SCI_MARKERNEXT, 0, MARGIN_BOOKMARK_MASKN); if (find_line != LINE_NOT_FOUND) @@ -1275,7 +1277,7 @@ on_search_page_mark(eu_tabpage *pnode, char *szmark, int size) int offset = 0; sptr_t find_line = 0; sptr_t current_line = 0; - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { const sptr_t line = eu_sci_call(pnode, SCI_GETLINECOUNT, 0, 0); *szmark = 0; @@ -1299,7 +1301,7 @@ on_search_page_mark(eu_tabpage *pnode, char *szmark, int size) void on_search_update_mark(eu_tabpage *pnode, char *szmark) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { char *p = strtok(szmark, ";"); while (p) @@ -1313,7 +1315,7 @@ on_search_update_mark(eu_tabpage *pnode, char *szmark) void on_search_fold_kept(eu_tabpage *pnode, char *szfold, int size) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { int offset = 0; sptr_t header_line = 0; @@ -1338,7 +1340,7 @@ on_search_fold_kept(eu_tabpage *pnode, char *szfold, int size) void on_search_update_fold(eu_tabpage *pnode, char *szfold) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { char *p = strtok(szfold, ";"); while (p) @@ -1766,7 +1768,7 @@ on_search_regxp_error(void) } if (hwnd_regxp_tips && on_dark_enable()) { - on_dark_set_theme(hwnd_regxp_tips, L"DarkMode_Explorer", NULL); + on_dark_set_theme(hwnd_regxp_tips, DARKMODE, NULL); } } else if ((ll_msg = on_search_regxp_msg()) != NULL) @@ -2066,7 +2068,7 @@ on_search_process_count(eu_tabpage *pnode, const char *key, const bool sel, cons static void on_search_report_result(eu_tabpage *pnode, const int button) { - if (pnode || !pnode->hex_mode) + if (pnode || !TAB_HEX_MODE(pnode)) { int file_count = 0; sptr_t match_count = 0; @@ -2338,7 +2340,7 @@ on_search_find_button(eu_tabpage *pnode, const char *dlg_text, const int button) { reverse = true; } - if (pnode->hex_mode) + if (TAB_HEX_MODE(pnode)) { return on_search_hexview(pnode, dlg_text, reverse) > 0; } @@ -2381,7 +2383,7 @@ on_search_max_line(void) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && p->match_count > 0) + if (p && !TAB_HEX_MODE(p) && p->match_count > 0) { const int max_line = (const int)cvector_size(p->ret_vec); const int k = max_line > 0 ? util_count_number(p->ret_vec[max_line - 1].line + 1) : 0; @@ -2542,7 +2544,7 @@ on_search_lookup_result(eu_tabpage *pnode, const bool all_file, const int count) for (; index < count; ++index) { p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && p->match_count > 0 && p->ret_vec) + if (p && !TAB_HEX_MODE(p) && p->match_count > 0 && p->ret_vec) { if (p != pnode) { @@ -2568,7 +2570,7 @@ on_search_lookup_result(eu_tabpage *pnode, const bool all_file, const int count) for (index = 0; index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && p->match_count > 0) + if (p && !TAB_HEX_MODE(p) && p->match_count > 0) { if (p != pnode) { @@ -2636,7 +2638,7 @@ on_search_find_next_button(const int button) { if (on_search_find_button(pnode, key, button)) { - if (!pnode->hex_mode) + if (!TAB_HEX_MODE(pnode)) { sptr_t lineno = 0; sptr_t row = 0; @@ -2648,7 +2650,7 @@ on_search_find_next_button(const int button) } } } - else if (!pnode->hex_mode) + else if (!TAB_HEX_MODE(pnode)) { on_search_find_error(pnode, button); } @@ -3406,7 +3408,7 @@ on_search_find_all_button(void* lp) goto res_clean; } pos = (float)(100.0/count); - if ((data = (uint8_t *) calloc(1, BUFF_SIZE+1)) == NULL) + if ((data = (uint8_t *) calloc(1, BUFF_8M+1)) == NULL) { goto res_clean; } @@ -3434,7 +3436,7 @@ on_search_find_all_button(void* lp) { continue; } - while ((readlen = fread((char *) data, 1, BUFF_SIZE, fp)) > 0) + while ((readlen = fread((char *) data, 1, BUFF_8M, fp)) > 0) { if (inpcre) { @@ -3589,7 +3591,7 @@ on_search_dark_mode_init(HWND hdlg, bool dark) } if (hwnd_regxp_tips) { - on_dark_set_theme(hwnd_regxp_tips, dark ? L"DarkMode_Explorer": L"", NULL); + on_dark_set_theme(hwnd_regxp_tips, dark ? DARKMODE: L"", NULL); } UpdateWindowEx(hdlg); } @@ -3759,7 +3761,7 @@ on_search_orig_find_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) ShowWindow(hwnd_re_stc, SW_HIDE); on_search_set_tip(IDC_MSG_SEARCH_STR1); eu_tabpage *pnode = on_tabpage_focus_at(); - if (pnode && pnode->hex_mode) + if (pnode && TAB_HEX_MODE(pnode)) { Button_SetCheck(rexp, BST_UNCHECKED); EnableWindow(rexp, false); @@ -4033,7 +4035,7 @@ on_search_repalce_event(eu_tabpage *p, replace_event docase) for (int k = 0; k < count; ++k) { eu_tabpage *pnode = on_tabpage_get_ptr(v[k]); - if (pnode && !pnode->hex_mode && !pnode->plugin) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->plugin) { if (pnode->doc_ptr && pnode->doc_ptr->tab_width > 0) { diff --git a/src/eu_search.h b/src/eu_search.h index db17dc56..acf4b416 100644 --- a/src/eu_search.h +++ b/src/eu_search.h @@ -20,6 +20,7 @@ #define _H_SKYLARK_SEARCH_ #define SELECTION_ZOOM_LEVEEL -99 +#define LINE_NOT_FOUND ((sptr_t)-1) #define ON_LOOP_FLAGS 0x00000010 #define ON_HEX_STRINGS 0x00000020 @@ -88,6 +89,7 @@ int on_search_back_navigate_all(void); int on_search_add_navigate_list(eu_tabpage *pnode, int64_t pos); int on_search_combo_callback(void *data, int count, char **column, char **names); +sptr_t on_search_marker_next(eu_tabpage *pnode, const sptr_t line, sptr_t last, const int bitmask); sptr_t on_search_process_find(eu_tabpage *, const char *, size_t, size_t, size_t); bool on_search_create_box(void); diff --git a/src/eu_settings.c b/src/eu_settings.c index 64ecb618..6f35491e 100644 --- a/src/eu_settings.c +++ b/src/eu_settings.c @@ -49,7 +49,7 @@ on_setting_load_icon(const TCHAR *path) const int scx = Scintilla_GetSystemMetricsForDpi(SM_CXSMICON, dpi); const int scy = Scintilla_GetSystemMetricsForDpi(SM_CYSMICON, dpi); // Load the file from which to copy the icon. - while (!_tcsicmp(util_path_ext(path), _T("exe"))) + while (WCSICMP(util_path_ext(path), ==, _T("exe"))) { // Note: LoadLibrary should have a fully explicit path. if ((hexe = (HINSTANCE)LoadLibrary(path)) == NULL) @@ -196,10 +196,13 @@ on_setting_update_menu(const HMENU setting_menu) pconf->m_customize[i].posid = IDM_SET_SETTINGS_CONFIG + count; if (pconf->m_customize[i].micon >= IDM_LUAJIT_ICON) { + pconf->m_customize[i].hbmp ? DeleteObject((HBITMAP)pconf->m_customize[i].hbmp) : (void)0; pconf->m_customize[i].hbmp = (uintptr_t)on_setting_lua_icon(pconf->m_customize[i].micon); } else if (!pconf->m_customize[i].micon && (path = util_to_abs(pconf->m_customize[i].path))) { + eu_logmsg("%s: path[%s]\n", __FUNCTION__, eu_utf16_utf8(path, NULL)); + pconf->m_customize[i].hbmp ? DeleteObject((HBITMAP)pconf->m_customize[i].hbmp) : (void)0; pconf->m_customize[i].hbmp = (uintptr_t)on_setting_load_icon(path); } if (pconf->m_customize[i].hbmp && pconf->m_customize[i].posid > 0) @@ -231,6 +234,7 @@ on_setting_execute(HWND hwnd, const int wm_id) { TCHAR *p = NULL; TCHAR *plugin = NULL; + size_t vec_len = 0; TCHAR *path = util_to_abs(pconf->m_customize[i].path); if (path) { @@ -252,14 +256,20 @@ on_setting_execute(HWND hwnd, const int wm_id) on_setting_parser_args(pconf->m_customize[i].param, &cmd_vec); if (wine && (plugin = util_winexy_get())) { - _sntprintf(cmd_exec, MAX_BUFFER, L"%s \"%s\"", plugin, path); + if (pconf->m_customize[i].hide) + { + _sntprintf(cmd_exec, MAX_BUFFER, L"%s %s \"%s\"", plugin, L"hide.exe", path); + } + else + { + _sntprintf(cmd_exec, MAX_BUFFER, L"%s \"%s\"", plugin, path); + } } else { _sntprintf(cmd_exec, MAX_BUFFER, _T("%s"), path); } - size_t vec_len = cvector_size(cmd_vec); - if (vec_len > 0) + if ((vec_len = cvector_size(cmd_vec)) > 0) { for (size_t k = 0; k < vec_len; ++k) { @@ -277,7 +287,14 @@ on_setting_execute(HWND hwnd, const int wm_id) { if (wine && (plugin = util_winexy_get())) { - _sntprintf(cmd_exec, MAX_BUFFER, L"%s \"%s\"", plugin, path); + if (pconf->m_customize[i].hide) + { + _sntprintf(cmd_exec, MAX_BUFFER, L"%s %s \"%s\"", plugin, L"hide.exe", path); + } + else + { + _sntprintf(cmd_exec, MAX_BUFFER, L"%s \"%s\"", plugin, path); + } } else { diff --git a/src/eu_share.c b/src/eu_share.c index 5baab0c6..0b5bb8a7 100644 --- a/src/eu_share.c +++ b/src/eu_share.c @@ -121,7 +121,7 @@ share_envent_create(void) } void -share_envent_set(bool signaled) +share_envent_set(const bool signaled) { if (signaled) { @@ -219,8 +219,7 @@ share_send_msg(void *param) { HWND hwnd = eu_module_hwnd(); if (!hwnd) - { - // 等待主窗口初始化 + { // 等待主窗口初始化 share_envent_wait(8000); } if ((hwnd = eu_module_hwnd()) != NULL) diff --git a/src/eu_snippet.c b/src/eu_snippet.c index a063523d..954a91d9 100644 --- a/src/eu_snippet.c +++ b/src/eu_snippet.c @@ -702,7 +702,7 @@ on_snippet_proc(HWND hdlg, uint32_t msg, WPARAM wParam, LPARAM lParam) } if (hwnd_lst) { - on_dark_set_theme(hwnd_lst, L"DarkMode_Explorer", NULL); + on_dark_set_theme(hwnd_lst, DARKMODE, NULL); } UpdateWindowEx(hdlg); } diff --git a/src/eu_splitter.c b/src/eu_splitter.c index 765a16dc..edd24a3a 100644 --- a/src/eu_splitter.c +++ b/src/eu_splitter.c @@ -23,8 +23,14 @@ HWND g_splitter_symbar = NULL; HWND g_splitter_editbar = NULL; HWND g_splitter_tablebar = NULL; -static void -on_splitter_drawing(HWND hwnd, HDC hdc) +static inline int +on_splitter_tree_line(void) +{ + return (3 * SPLIT_WIDTH); +} + +static inline void +on_splitter_drawing(const HWND hwnd, const HDC hdc) { RECT rc = {0}; GetClientRect(hwnd, &rc); @@ -32,17 +38,16 @@ on_splitter_drawing(HWND hwnd, HDC hdc) } static void -on_splitter_rect_box(HWND hwnd, LPRECT r, int offset) +on_splitter_rect_box(HWND hwnd, LPRECT r, const int offset) { RECT rc_tree = {0}; RECT rc_main = {0}; RECT rc_client = {0}; POINT client_top = {0}; - on_treebar_adjust_box(&rc_tree); + on_treebar_adjust_box(&rc_tree, &rc_client); GetWindowRect(hwnd, &rc_main); - GetClientRect(hwnd, &rc_client); ClientToScreen(hwnd, &client_top); - int toolbar_height = on_toolbar_height(); + int toolbar_height = on_toolbar_get_height(); int tree_hight = rc_client.bottom - rc_client.top - SPLIT_WIDTH - toolbar_height - on_statusbar_height() - offset; r->left = rc_tree.left; r->right = rc_tree.right; @@ -50,14 +55,14 @@ on_splitter_rect_box(HWND hwnd, LPRECT r, int offset) r->bottom = r->top + tree_hight; } -static int -on_splitter_absolute_height(int y) +static inline int +on_splitter_absolute_height(const int y) { - return y + menu_height() + on_toolbar_height() + 5; + return y + menu_height() + on_toolbar_get_height() + 5; } static HDC -on_splitter_drawing_line(HWND parent, LPRECT r, int x, HPEN *ptr_pen) +on_splitter_drawing_line(HWND parent, LPRECT r, const int x, HPEN *ptr_pen) { HDC hdc = GetWindowDC(parent); HPEN hpen = CreatePen(PS_SOLID, SPLIT_WIDTH, 0); @@ -78,6 +83,15 @@ on_splitter_drawing_line(HWND parent, LPRECT r, int x, HPEN *ptr_pen) return hdc; } +static inline void +on_splitter_paint(const HWND hwnd) +{ + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + on_splitter_drawing(hwnd, hdc); + EndPaint(hwnd, &ps); +} + static LRESULT CALLBACK on_splitter_callback_treebar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -86,18 +100,15 @@ on_splitter_callback_treebar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { case WM_PAINT: { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - on_splitter_drawing(hwnd, hdc); - EndPaint(hwnd, &ps); + on_splitter_paint(hwnd); break; } case WM_LBUTTONDOWN: { RECT rect_tree; HWND parent = GetParent(hwnd); - on_treebar_adjust_box(&rect_tree); - x = rect_tree.right - rect_tree.left + 3 * SPLIT_WIDTH; + on_treebar_adjust_box(&rect_tree, NULL); + x = rect_tree.right - rect_tree.left + on_splitter_tree_line(); HDC hdc = on_splitter_drawing_line(parent, &rect_tree, x, NULL); ReleaseDC(parent, hdc); SetCapture(hwnd); @@ -115,6 +126,7 @@ on_splitter_callback_treebar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { eu_get_config()->file_tree_width = FILETREEBAR_WIDTH_MIN; } + on_treebar_size(); eu_window_resize(parent); break; } @@ -126,7 +138,7 @@ on_splitter_callback_treebar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) HWND parent = GetParent(hwnd); HPEN hpen = NULL; HDC hdc = on_splitter_drawing_line(parent, &rect_tree, x, &hpen); - x = rect_tree.right - rect_tree.left + (short)LOWORD(lParam); + x = rect_tree.right - rect_tree.left + on_splitter_tree_line() + (short)LOWORD(lParam); MoveToEx(hdc, x, rect_tree.top, NULL); LineTo(hdc, x, rect_tree.bottom); if (hpen) @@ -138,6 +150,11 @@ on_splitter_callback_treebar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } break; } + case WM_DESTROY: + { + eu_logmsg("on_splitter_callback_treebar WM_DESTROY\n"); + x = 0; + } default: { return DefWindowProc(hwnd, msg, wParam, lParam); @@ -155,10 +172,7 @@ on_splitter_callback_symbar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { case WM_PAINT: { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - on_splitter_drawing(hwnd, hdc); - EndPaint(hwnd, &ps); + on_splitter_paint(hwnd); break; } case WM_LBUTTONDOWN: @@ -170,11 +184,11 @@ on_splitter_callback_symbar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (pnode->sym_show) { - cx = pnode->rect_sym.left + 3 * SPLIT_WIDTH; + cx = pnode->rect_sym.left + on_splitter_tree_line(); } else if (pnode->map_show) { - cx = pnode->rect_map.left + 3 * SPLIT_WIDTH; + cx = pnode->rect_map.left + on_splitter_tree_line(); } else { @@ -247,16 +261,17 @@ on_splitter_callback_symbar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) LineTo(hdc, cx, r.bottom); if (pnode->sym_show) { - cx = pnode->rect_sym.left + (short)LOWORD(lParam); + cx = pnode->rect_sym.left + (short)LOWORD(lParam) + on_splitter_tree_line(); } else if (pnode->map_show) { - cx = pnode->rect_map.left + (short)LOWORD(lParam); + cx = pnode->rect_map.left + (short)LOWORD(lParam) + on_splitter_tree_line(); } else { - cx = pnode->rect_sc.right + (short)LOWORD(lParam); + cx = pnode->rect_sc.right + (short)LOWORD(lParam) + on_splitter_tree_line(); } + /* 这里应该限制cx, 不要覆盖treebar */ MoveToEx(hdc, cx, r.top, NULL); LineTo(hdc, cx, r.bottom); SelectObject(hdc, hold_pen); @@ -284,10 +299,7 @@ on_splitter_callback_editbar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { case WM_PAINT: { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - on_splitter_drawing(hwnd, hdc); - EndPaint(hwnd, &ps); + on_splitter_paint(hwnd); break; } case WM_LBUTTONDOWN: @@ -370,10 +382,7 @@ on_splitter_callback_tablebar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { case WM_PAINT: { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - on_splitter_drawing(hwnd, hdc); - EndPaint(hwnd, &ps); + on_splitter_paint(hwnd); break; } case WM_LBUTTONDOWN: @@ -457,6 +466,27 @@ on_splitter_register(const TCHAR *classname, WNDPROC proc, int cur_id) return (RegisterClassEx(&wcex) > 0); } +void +on_splitter_redraw(void) +{ + if (g_splitter_treebar) + { + UpdateWindowEx(g_splitter_treebar); + } + if (g_splitter_symbar) + { + UpdateWindowEx(g_splitter_symbar); + } + if (g_splitter_editbar) + { + UpdateWindowEx(g_splitter_editbar); + } + if (g_splitter_tablebar) + { + UpdateWindowEx(g_splitter_tablebar); + } +} + bool on_splitter_init_treebar(HWND parent) { @@ -469,7 +499,7 @@ on_splitter_init_treebar(HWND parent) bool on_splitter_init_symbar(HWND parent) { - const TCHAR *splite_class = _T("splitter_scintilla_symbar"); + const TCHAR *splite_class = _T("splitter_symbar_scintilla"); on_splitter_register(splite_class, on_splitter_callback_symbar, IDC_CURSOR_WE); g_splitter_symbar = CreateWindowEx(0, splite_class, _T(""), WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 0, 0, parent, 0, eu_module_handle(), 0); return (g_splitter_symbar != NULL); diff --git a/src/eu_splitter.h b/src/eu_splitter.h index ecb757dd..5b6ad845 100644 --- a/src/eu_splitter.h +++ b/src/eu_splitter.h @@ -33,6 +33,7 @@ bool on_splitter_init_treebar(HWND parent); bool on_splitter_init_symbar(HWND parent); bool on_splitter_init_editbar(HWND parent); bool on_splitter_init_tablebar(HWND parent); +void on_splitter_redraw(void); HWND on_splitter_init_window(HWND parent, const TCHAR *class_name, const int flags, HMENU hmenu, WNDPROC proc, void *lp); #ifdef __cplusplus diff --git a/src/eu_sql.h b/src/eu_sql.h index 2329bf99..806ca6fe 100644 --- a/src/eu_sql.h +++ b/src/eu_sql.h @@ -37,7 +37,7 @@ typedef enum _DB_MODE typedef struct _file_recent { - bool hex; + int hex; char path[MAX_BUFFER]; int64_t postion; }file_recent; diff --git a/src/eu_statusbar.c b/src/eu_statusbar.c index 23b915ec..fa115e40 100644 --- a/src/eu_statusbar.c +++ b/src/eu_statusbar.c @@ -35,8 +35,6 @@ HWND g_statusbar = NULL; static HMENU g_menu_break; static HMENU g_menu_code; static HMENU g_menu_type; -static HFONT hfont_btn; -static int g_status_height; void on_statusbar_btn_colour(eu_tabpage *pnode, bool only_read) @@ -52,7 +50,7 @@ on_statusbar_btn_colour(eu_tabpage *pnode, bool only_read) instance_theme theme = {0, (uint32_t)eu_get_theme()->item.text.bgcolor}; np_plugins_setvalue(&pnode->plugin->funcs, &pnode->plugin->npp, NV_ATTRIB_CHANGE, &theme); } - else if (pnode->hex_mode) + else if (TAB_HEX_MODE(pnode)) { SendMessage(pnode->hwnd_sc, HVM_SETBKCOLOR, 0, (LPARAM)eu_get_theme()->item.text.bgcolor); } @@ -74,7 +72,7 @@ on_statusbar_btn_colour(eu_tabpage *pnode, bool only_read) instance_theme theme = {1, 0x482730 /* STATUS_STATIC_FOCUS convert BGR */}; np_plugins_setvalue(&pnode->plugin->funcs, &pnode->plugin->npp, NV_ATTRIB_CHANGE, &theme); } - else if (pnode->hex_mode) + else if (TAB_HEX_MODE(pnode)) { SendMessage(pnode->hwnd_sc, HVM_SETBKCOLOR, 0, (LPARAM)STATUS_STATIC_FOCUS); } @@ -188,19 +186,15 @@ on_statusbar_set_text(HWND hwnd, const uint8_t part, LPCTSTR lpsz) } } -void -on_statusbar_adjust_box(void) +int +on_statusbar_height(void) { - if (!eu_get_config()->m_statusbar) - { - g_status_height = 0; - } - else if (g_statusbar) + int status_height = 0; + if (g_statusbar && eu_get_config()->m_statusbar) { - RECT rc = {0}; - GetClientRect(g_statusbar, &rc); - g_status_height = rc.bottom - rc.top; + status_height = eu_dpi_scale_xy(0, STATUSBAR_DEFHIGHT); } + return status_height; } static void @@ -209,49 +203,68 @@ on_statusbar_adjust_btn(int left, int right) HWND hrw = GetDlgItem(g_statusbar, IDM_BTN_RW); if (hrw) { - int btn_height = 0; - int dpi = eu_get_dpi(g_statusbar); - int btn_width = eu_dpi_scale_xy(dpi > 96 ? dpi - dpi/4 : dpi, BTN_DEFAULT_WIDTH); - RECT rc_part = {0}; - SendMessage(g_statusbar, SB_GETRECT, STATUSBAR_DOC_BTN, (LPARAM)&rc_part); - btn_height = rc_part.bottom - SPLIT_WIDTH; - left = right - btn_width - 12; - MoveWindow(hrw, left, SPLIT_WIDTH, btn_width, btn_height, TRUE); - ShowWindow(hrw, SW_SHOW); + if (left || right) + { + int btn_height = 0; + int dpi = eu_get_dpi(g_statusbar); + int btn_width = eu_dpi_scale_xy(dpi > 96 ? dpi - dpi/4 : dpi, BTN_DEFAULT_WIDTH); + RECT rc_part = {0}; + SendMessage(g_statusbar, SB_GETRECT, STATUSBAR_DOC_BTN, (LPARAM)&rc_part); + btn_height = rc_part.bottom - SPLIT_WIDTH; + left = right - btn_width - 1; + eu_setpos_window(hrw, HWND_TOP, left, SPLIT_WIDTH, btn_width, btn_height, SWP_SHOWWINDOW); + } + else + { + eu_setpos_window(hrw, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); + } } } void -on_statusbar_refresh(void) +on_statusbar_size(eu_tabpage *pnode) { - if (g_statusbar && eu_get_config()->m_statusbar) + if (g_statusbar) { - HWND hwnd = eu_module_hwnd(); - RECT rc_main = {0}; - GetWindowRect(hwnd, &rc_main); - int cx = rc_main.right - rc_main.left; - int n_half = cx / 8; - int btn_half = n_half*7+70; - int parts[] = {n_half*2, n_half*3, n_half*4, n_half*5+20, n_half*6+20, btn_half, -1}; - SendMessage(g_statusbar, SB_SETPARTS, STATUSBAR_PART, (LPARAM)&parts); - on_statusbar_adjust_btn(btn_half, cx); + if (!eu_get_config()->m_statusbar) + { + on_statusbar_adjust_btn(0, 0); + eu_setpos_window(g_statusbar, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); + } + else if (pnode) + { + on_statusbar_btn_rw(pnode, true); + } + else + { + RECT rc = {0}; + GetClientRect(eu_hwnd_self(), &rc); + const int height = on_statusbar_height(); + int cx = rc.right - rc.left; + int n_half = cx / 8; + int btn_half = n_half*7+70; + int parts[] = {n_half*2, n_half*3, n_half*4, n_half*5+20, n_half*6+20, btn_half, -1}; + SendMessage(g_statusbar, SB_SETPARTS, STATUSBAR_PART, (LPARAM)&parts); + on_statusbar_adjust_btn(btn_half, cx); + MoveWindow(g_statusbar, 0, rc.bottom - height, cx, height, TRUE); + ShowWindow(g_statusbar, SW_SHOW); + } } } static bool -on_statusbar_create_button(HWND hstatus) +on_statusbar_create_button(const HWND hstatus) { RECT rc = {0}; TCHAR wstr[EDITNUMBS] = {0}; HWND hrw = NULL; - if (!eu_i18n_load_str(IDS_BUTTON_W, wstr, EDITNUMBS)) + if (eu_i18n_load_str(IDS_BUTTON_W, wstr, EDITNUMBS)) { - return false; - } - hrw = CreateWindowEx(0, _T("button"), wstr, WS_CHILD | WS_CLIPSIBLINGS | BS_FLAT, 0, 0, 0, 0, hstatus, (HMENU) IDM_BTN_RW, eu_module_handle(), NULL); - if (!hrw) - { - eu_logmsg("%s: CreateWindowEx IDM_BTN_RW failed\n", __FUNCTION__); + hrw = CreateWindowEx(0, _T("button"), wstr, WS_CHILD | WS_CLIPSIBLINGS | BS_FLAT, 0, 0, 0, 0, hstatus, (HMENU) IDM_BTN_RW, eu_module_handle(), NULL); + if (hrw) + { + on_theme_update_font(btn_id); + } } return (hrw != NULL); } @@ -379,39 +392,25 @@ on_statusbar_pop_menu(int parts, LPPOINT pt) } } -static HFONT -on_statusbar_default_font(void) -{ - if (!hfont_btn) - { - LOGFONT logfont = {eu_dpi_scale_font()}; - logfont.lfWeight = FW_NORMAL; - logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; - logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; - logfont.lfQuality = CLEARTYPE_QUALITY; - logfont.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; - logfont.lfCharSet = ANSI_CHARSET; - _tcsncpy(logfont.lfFaceName, _T("MS Shell Dlg"), _countof(logfont.lfFaceName)-1); - hfont_btn = CreateFontIndirect(&logfont); - } - return hfont_btn; -} - -static void -on_statusbar_update_btn(HWND hwnd) -{ - if (hfont_btn || (on_statusbar_default_font())) - { - SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont_btn, 0); - } -} - static LRESULT CALLBACK on_statusbar_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR sub_id, DWORD_PTR dw) { eu_tabpage *pnode = NULL; switch (message) { + case WM_CREATE: + { + if (on_dark_enable()) + { + on_statusbar_size(NULL); + on_dark_set_theme(g_statusbar, L"Explorer", NULL); + } + else + { + SendMessage(hwnd, WM_SETFONT, (WPARAM)on_theme_font_hwnd(), 0); + } + break; + } case WM_ERASEBKGND: { if (!on_dark_enable()) @@ -433,12 +432,10 @@ on_statusbar_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PT sb_borders borders = {0}; const COLORREF edge_color = 0x646464; SendMessage(hwnd, SB_GETBORDERS, 0, (LPARAM)&borders); - intptr_t style = GetWindowLongPtr(hwnd, GWL_STYLE); - bool is_grip = style & SBARS_SIZEGRIP; HDC hdc = BeginPaint(hwnd, &ps); HPEN hpen = CreatePen(PS_SOLID, 1, edge_color); HPEN hold_pen = (HPEN)(SelectObject(hdc, hpen)); - HFONT hold_font = (HFONT)SelectObject(hdc, on_statusbar_default_font()); + HFONT hold_font = (HFONT)SelectObject(hdc, on_theme_font_hwnd()); FillRect(hdc, &ps.rcPaint, (HBRUSH)on_dark_get_bgbrush()); wchar_t str[MAX_PATH] = {0}; int nparts = (int)SendMessage(hwnd, SB_GETPARTS, 0, 0); @@ -469,7 +466,7 @@ on_statusbar_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PT rc_part.left += borders.between; rc_part.right -= borders.vertical; DrawText(hdc, str, eu_int_cast(wcslen(str)), &rc_part, DT_SINGLELINE | DT_VCENTER | DT_LEFT); - if (!is_grip && i < (nparts - 1)) + if (i < nparts) { FillRect(hdc, &rc_divider, (HBRUSH)on_dark_get_hot_brush()); } @@ -480,21 +477,6 @@ on_statusbar_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PT EndPaint(hwnd, &ps); return 0; } - case WM_STATUS_REFRESH: - { - on_statusbar_refresh(); - return 1; - } - case WM_MOVE: - { - on_statusbar_refresh(); - on_statusbar_update(); - break; - } - case WM_SIZE: - { - break; - } case WM_COMMAND: { if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDM_BTN_RW) @@ -503,8 +485,7 @@ on_statusbar_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PT { on_statusbar_btn_rw(pnode, false); // Maybe affect this part, refresh it - on_statusbar_update_filesize(pnode); - PostMessage(eu_module_hwnd(), WM_ACTIVATE, MAKEWPARAM(WA_CLICKACTIVE, 0), 0); + on_proc_msg_active(pnode); } return 1; } @@ -628,6 +609,7 @@ on_statusbar_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PT case IDM_OTHER_3: case IDM_OTHER_ANSI: case IDM_OTHER_BIN: + case IDM_OTHER_PLUGIN: case IDM_UNKNOWN: if (!on_statusbar_convert_coding(pnode, id_menu)) { @@ -639,27 +621,14 @@ on_statusbar_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PT } break; } - case WM_CTLCOLORBTN: - { - on_statusbar_update_btn((HWND)lParam); - return 1; - } case WM_SETTINGCHANGE: { - if (on_dark_enable() && on_dark_color_scheme_change(lParam)) - { - SendMessage(hwnd, WM_THEMECHANGED, 0, 0); - } + SendMessage(hwnd, WM_THEMECHANGED, 0, 0); break; } case WM_THEMECHANGED: { - if (on_dark_enable()) - { - on_dark_allow_window(hwnd, true); - on_statusbar_dark_release(false); - UpdateWindow(hwnd); - } + on_statusbar_dark_mode(on_dark_enable()); break; } case WM_NCDESTROY: @@ -687,11 +656,6 @@ on_statusbar_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PT g_menu_type = NULL; } DestroyWindow(GetDlgItem(hwnd, IDM_BTN_RW)); - if (hfont_btn) - { - DeleteObject(hfont_btn); - hfont_btn = NULL; - } g_statusbar = NULL; } break; @@ -740,7 +704,7 @@ on_statusbar_update_line(eu_tabpage *pnode) { return; } - if (pnode->hex_mode) + if (TAB_HEX_MODE(pnode)) { eu_i18n_load_str(IDS_STATUS_HXY, m_xy, 0); _sntprintf(s_xy, FILESIZE-1, m_xy, SendMessage(pnode->hwnd_sc, HVM_GETHEXADDR, 0, 0)); @@ -792,14 +756,14 @@ on_statusbar_update_filesize(eu_tabpage *pnode) } else { - LOAD_I18N_RESSTR(pnode->hex_mode? IDS_STATUS_HLC : IDS_STATUS_LC, s_lc); - if (!pnode->hex_mode) + LOAD_I18N_RESSTR(TAB_HAS_TXT(pnode) ? IDS_STATUS_LC : IDS_STATUS_HLC, s_lc); + if (TAB_HAS_TXT(pnode)) { _sntprintf(file_size, FILESIZE, s_lc, nsize, eu_sci_call(pnode, SCI_GETCURRENTPOS, 0, 0)); } else { - _sntprintf(file_size, FILESIZE, s_lc, pnode->pmod ? (sptr_t)pnode->raw_size : nsize); + _sntprintf(file_size, FILESIZE, s_lc, pnode->pmod ? (sptr_t)pnode->raw_size : nsize); } } if (*file_size) @@ -815,7 +779,7 @@ on_statusbar_update_eol(eu_tabpage *pnode, const int eol) { return; } - if(pnode->hex_mode) + if(TAB_HEX_MODE(pnode) || pnode->plugin) { TCHAR buf[] = {0xA554, 0x0020, _T('N'), _T('a'), _T('N'), 0}; on_statusbar_set_text(g_statusbar, STATUSBAR_DOC_EOLS, buf); @@ -865,20 +829,16 @@ on_statusbar_update_filetype_menu(eu_tabpage *pnode) } void -on_statusbar_update_coding(eu_tabpage *pnode, const int res_id) +on_statusbar_update_coding(eu_tabpage *pnode) { int type = IDM_UNKNOWN; if (!(g_statusbar && pnode && eu_get_config()->m_statusbar)) { return; } - if (res_id) - { - type = res_id; - } - else if (pnode && pnode->codepage) + if (pnode) { - type = pnode->codepage; + type = TAB_HEX_MODE(pnode) ? IDM_OTHER_BIN : pnode->codepage; } switch (type) { @@ -944,6 +904,7 @@ on_statusbar_update_coding(eu_tabpage *pnode, const int res_id) case IDM_OTHER_3: case IDM_OTHER_ANSI: case IDM_OTHER_BIN: + case IDM_OTHER_PLUGIN: case IDM_UNKNOWN: on_statusbar_menu_check(g_menu_code, IDM_OTHER_HZ, IDM_UNKNOWN, type, 5, STATUSBAR_DOC_ENC); break; @@ -952,7 +913,7 @@ on_statusbar_update_coding(eu_tabpage *pnode, const int res_id) } } -static void +static bool on_statusbar_create_filetype_menu(void) { if (g_menu_type) @@ -977,22 +938,18 @@ on_statusbar_create_filetype_menu(void) free(desc); } } + return true; } -} - -int -on_statusbar_height(void) -{ - return g_status_height; + return false; } void -on_statusbar_update(void) +on_statusbar_update(eu_tabpage *psrc) { + eu_tabpage *pnode = psrc; if (g_statusbar && eu_get_config()->m_statusbar) { - eu_tabpage *pnode = on_tabpage_focus_at(); - if (pnode && pnode->hwnd_sc) + if ((pnode || (pnode = on_tabpage_focus_at())) && pnode->hwnd_sc) { SendMessage(g_statusbar, WM_SETREDRAW, FALSE, 0); on_statusbar_update_fileinfo(pnode, NULL); @@ -1000,7 +957,7 @@ on_statusbar_update(void) on_statusbar_update_filesize(pnode); on_statusbar_update_eol(pnode, -1); on_statusbar_update_filetype_menu(pnode); - on_statusbar_update_coding(pnode, pnode->hex_mode ? IDM_OTHER_BIN : 0); + on_statusbar_update_coding(pnode); SendMessage(g_statusbar, WM_SETREDRAW, TRUE, 0); RedrawWindow(g_statusbar, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); } @@ -1018,42 +975,24 @@ on_statusbar_destroy(void) } void -on_statusbar_dark_mode(void) +on_statusbar_dark_mode(const bool dark) { - if (g_statusbar && on_dark_enable()) - { - const int buttons[] = {IDM_BTN_RW}; - for (int id = 0; id < _countof(buttons); ++id) - { - HWND btn = GetDlgItem(g_statusbar, buttons[id]); - on_dark_set_theme(btn, L"Explorer", NULL); - } - on_dark_set_theme(g_statusbar, L"Explorer", NULL); - } -} - -void -on_statusbar_dark_release(bool off) -{ - const int buttons[] = {IDM_BTN_RW}; - for (int id = 0; id < _countof(buttons); ++id) - { - HWND btn = GetDlgItem(g_statusbar, buttons[id]); - on_dark_allow_window(btn, !off); - SendMessage(btn, WM_THEMECHANGED, 0, 0); - } + HWND btn = GetDlgItem(g_statusbar, IDM_BTN_RW); + on_dark_allow_window(g_statusbar, dark); + on_dark_allow_window(btn, dark); + on_dark_set_theme(btn, L"Explorer", NULL); } -bool -on_statusbar_init(HWND hwnd) +int +on_statusbar_create_dlg(HWND hwnd) { - bool ret = false; - const uint32_t dw_style = SBT_NOBORDERS | WS_CHILD | SBARS_SIZEGRIP; + int ret = 1; + const uint32_t style = SBT_NOBORDERS | WS_CHILD; if (g_statusbar) { DestroyWindow(g_statusbar); } - g_statusbar = CreateWindowEx(WS_EX_COMPOSITED, STATUSCLASSNAME, NULL, dw_style, 0, 0, 0, 0, hwnd, (HMENU)IDC_STATUSBAR, eu_module_handle(), 0); + g_statusbar = CreateWindowEx(WS_EX_COMPOSITED, STATUSCLASSNAME, NULL, style, 0, 0, 0, 0, hwnd, (HMENU)IDC_STATUSBAR, eu_module_handle(), 0); do { if (!g_statusbar) @@ -1072,14 +1011,17 @@ on_statusbar_init(HWND hwnd) eu_logmsg("%s: create menu failed\n", __FUNCTION__); break; } - on_statusbar_create_filetype_menu(); - ret = on_statusbar_create_button(g_statusbar); + if (!(on_statusbar_create_filetype_menu())) + { + eu_logmsg("%s: on_statusbar_create_filetype_menu failed\n", __FUNCTION__); + break; + } + if (!on_statusbar_create_button(g_statusbar)) + { + eu_logmsg("%s: on_statusbar_create_button failed\n", __FUNCTION__); + break; + } + ret = 0; } while(0); - if (ret && on_dark_enable()) - { - on_statusbar_dark_mode(); - SendMessage(g_statusbar, WM_STATUS_REFRESH, 0, 0); - on_statusbar_update(); - } return ret; } diff --git a/src/eu_statusbar.h b/src/eu_statusbar.h index 11cf1e2b..f3ee3ed9 100644 --- a/src/eu_statusbar.h +++ b/src/eu_statusbar.h @@ -19,6 +19,7 @@ #ifndef _EU_STATUSBAR_H_ #define _EU_STATUSBAR_H_ +#define STATUSBAR_DEFHIGHT 22 #define STATUSBAR_DOC_INFO 0 #define STATUSBAR_DOC_POS 1 #define STATUSBAR_DOC_EOLS 2 @@ -40,20 +41,19 @@ extern "C" { extern HWND g_statusbar; -bool on_statusbar_init(HWND hwnd); +int on_statusbar_create_dlg(HWND hwnd); int on_statusbar_height(void); int on_statusbar_btn_rw(eu_tabpage *pnode, bool m_auto); -void on_statusbar_refresh(void); -void on_statusbar_update(void); +void on_statusbar_size(eu_tabpage *pnode); +void on_statusbar_update(eu_tabpage *pnode); void on_statusbar_destroy(void); void on_statusbar_adjust_box(void); void on_statusbar_update_eol(eu_tabpage *pnode, const int eol); void on_statusbar_update_line(eu_tabpage *pnode); void on_statusbar_update_filesize(eu_tabpage *pnode); -void on_statusbar_update_coding(eu_tabpage *pnode, const int res_id); +void on_statusbar_update_coding(eu_tabpage *pnode); void on_statusbar_update_fileinfo(eu_tabpage *pnode, const TCHAR *print_str); -void on_statusbar_dark_mode(void); -void on_statusbar_dark_release(bool off); +void on_statusbar_dark_mode(const bool dark); void on_statusbar_pop_menu(int parts, LPPOINT pt); void on_statusbar_btn_colour(eu_tabpage *pnode, bool only_read); diff --git a/src/eu_tabpage.c b/src/eu_tabpage.c index e2be134d..a925e7b4 100644 --- a/src/eu_tabpage.c +++ b/src/eu_tabpage.c @@ -18,39 +18,34 @@ #include "framework.h" -#define TAB_MIN_TOP 4 -#define TAB_MIN_LEFT 40 -#define TAB_MIN_WIDTH 140 -#define CLOSEBUTTON_WIDTH 11 -#define CLOSEBUTTON_HEIGHT 11 +#define TAB_MIN_RIGHT 8 +#define TAB_MIN_LEFT 30 +#define TAB_MIN_WIDTH 160 +#define CLOSEBUTTON_DEFAULT 11 #define CX_ICON 16 #define CY_ICON 16 #define COLORREF2RGB(c) ((c & 0xff00) | ((c >> 16) & 0xff) | ((c << 16) & 0xff0000)) HWND g_tabpages = NULL; -static POINT g_point; +static POINT g_point = {0}; static WNDPROC old_tabproc = NULL; static bool tab_drag = false; static bool tab_mutil_select = false; -static volatile bool tab_do_drag; +static volatile bool tab_do_drag = false;; static volatile int tab_move_from = -1; static HCURSOR g_drag_hcursor = NULL; int on_tabpage_get_height(void) { - RECT rect_treebar; - GetClientRect(g_tabpages, &rect_treebar); - return (rect_treebar.bottom - rect_treebar.top); -} - -static int -on_tabpage_internal_height(void) -{ - RECT rect_tabbar = {0}; - int tab_height = TABS_HEIGHT_DEFAULT; - TabCtrl_GetItemRect(g_tabpages, 0, &rect_tabbar); - tab_height = (rect_tabbar.bottom - rect_tabbar.top) * TabCtrl_GetRowCount(g_tabpages); + int tab_height = eu_dpi_scale_xy(0, TABS_HEIGHT_DEFAULT); + if (g_tabpages) + { + RECT tabs = {0}; + int row = TabCtrl_GetRowCount(g_tabpages); + TabCtrl_GetItemRect(g_tabpages, 0, &tabs); + tab_height = row * (tabs.bottom - tabs.top) + (row > 1 ? (row - 1) * 3 + 1 : 1); + } return tab_height; } @@ -59,6 +54,10 @@ on_tabpage_has_drag(POINT *pt) { int x = pt->x - g_point.x; int y = pt->y - g_point.y; + if (!(g_point.x || g_point.y)) + { + return false; + } if (abs(x) > 3 || abs(y) > 3) { return true; @@ -153,6 +152,39 @@ on_tabpage_changing(int index) } } +static void +on_tabpage_get_padding(const HWND hwnd, const int index, RECT *prc) +{ + if (hwnd && prc) + { + TabCtrl_GetItemRect(hwnd, index, prc); + if (index > 0) + { + int diff = 0; + RECT pre_rc = {0}; + RECT pre_zero = {0}; + const bool split_hide = !eu_get_config()->m_tab_split; + split_hide ? TabCtrl_GetItemRect(hwnd, 0, &pre_zero) : (void)0; + TabCtrl_GetItemRect(hwnd, index - 1, &pre_rc); + if ((pre_rc.bottom == prc->bottom)) + { + if ((diff = prc->left - pre_rc.right) > 0) + { + prc->left -= diff; + } + if (split_hide && (diff = prc->top - pre_zero.top) > 0) + { + prc->top = pre_rc.top - 3; + } + } + else if (split_hide && (diff = prc->top - pre_rc.bottom) > 0) + { + prc->top -= diff; + } + } + } +} + static void on_tabpage_deselect(int index) { @@ -161,7 +193,7 @@ on_tabpage_deselect(int index) RECT rc; TCITEM tci = {TCIF_STATE, 0, TCIS_BUTTONPRESSED}; SendMessage(g_tabpages, TCM_SETITEM, index, (LPARAM)&tci); - TabCtrl_GetItemRect(g_tabpages, index, &rc); + on_tabpage_get_padding(g_tabpages, index, &rc); InvalidateRect(g_tabpages, &rc, true); } } @@ -181,6 +213,22 @@ on_tabpage_nfocus(int index) return false; } +static inline int +on_tabpage_close_size(void) +{ + return (util_under_wine() ? (CLOSEBUTTON_DEFAULT + TAB_MIN_RIGHT) : eu_dpi_scale_xy(0, CLOSEBUTTON_DEFAULT + TAB_MIN_RIGHT)); +} + +void +on_tabpage_variable_reset(void) +{ + tab_move_from = -1; + tab_drag = false; + tab_mutil_select = false; + tab_do_drag = false; + g_point.x = 0, g_point.y = 0; +} + int on_tabpage_sel_number(int **pvec, const bool ascending) { @@ -211,9 +259,9 @@ on_tabpage_sel_path(wchar_t ***pvec, bool *hex) if (on_tabpage_nfocus(i) && (p = on_tabpage_get_ptr(i)) && !p->is_blank && !url_has_remote(p->pathfile)) { cvector_push_back(*pvec, _wcsdup(p->pathfile)); - if (hex && p->hex_mode) + if (hex && TAB_HEX_MODE(p)) { - *hex = p->hex_mode; + *hex = p->hex_mode == TYPES_HEX; } ++num; } @@ -245,33 +293,31 @@ on_tabpage_active_one(int index) static void on_tabpage_draw_sign(const HDC hdc, const LPRECT lprect) { - const TCHAR *text = util_os_version() < 603 ? _T("x") : _T("✕"); - HFONT hfont = CreateFont(-14, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Arial")); - HGDIOBJ oldj = SelectObject(hdc, hfont); - RECT rc = {lprect->right - CLOSEBUTTON_WIDTH - TAB_MIN_TOP, - lprect->top + 1, + const TCHAR *text = util_os_version() < 603 || util_under_wine() ? _T("x") : _T("✕"); + HGDIOBJ oldj = SelectObject(hdc, on_theme_font_hwnd()); + RECT rc = {lprect->right - on_tabpage_close_size(), + lprect->top, lprect->right, lprect->bottom }; - DrawText(hdc, text, (int)_tcslen(text), &rc, DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); + DrawText(hdc, text, (int)_tcslen(text), &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); SelectObject(hdc, oldj); - DeleteObject(hfont); } static void on_tabpage_draw_close(HWND hwnd, const LPRECT lprect, bool sel) { HDC hdc = GetDC(hwnd); + const bool dark = on_dark_enable(); colour cr = 0; if (sel) { - cr = eu_get_theme()->item.activetab.bgcolor; + cr = !dark ? eu_get_theme()->item.activetab.bgcolor : eu_get_theme()->item.activetab.color; SetBkColor(hdc, cr); } else { - cr = set_btnface_color(hdc, on_dark_enable()); + cr = set_tabface_color(hdc, dark); } on_tabpage_draw_sign(hdc, lprect); ReleaseDC(hwnd, hdc); @@ -280,8 +326,8 @@ on_tabpage_draw_close(HWND hwnd, const LPRECT lprect, bool sel) static void on_tabpage_flush_close(HWND hwnd, const LPRECT lprect) { - RECT rc = {lprect->right - CLOSEBUTTON_WIDTH - TAB_MIN_TOP, - lprect->top + 1, + RECT rc = {lprect->right - on_tabpage_close_size(), + lprect->top, lprect->right, lprect->bottom }; @@ -291,8 +337,8 @@ on_tabpage_flush_close(HWND hwnd, const LPRECT lprect) static bool on_tabpage_hit_button(const LPRECT lprect, const LPPOINT pt) { - RECT rc = {lprect->right - CLOSEBUTTON_WIDTH - TAB_MIN_TOP, - lprect->top + 1, + RECT rc = {lprect->right - on_tabpage_close_size(), + lprect->top, lprect->right, lprect->bottom }; @@ -309,8 +355,8 @@ on_tabpage_hit_index(const LPPOINT pt) static void on_tabpage_paint_draw(HWND hwnd, HDC hdc) { - bool dark_mode = on_dark_enable(); - HGDIOBJ old_font = SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + const bool dark_mode = on_dark_enable(); + HGDIOBJ old_font = SelectObject(hdc, on_theme_font_hwnd()); while (old_font) { set_text_color(hdc, dark_mode); @@ -326,18 +372,17 @@ on_tabpage_paint_draw(HWND hwnd, HDC hdc) { break; } - TabCtrl_GetItemRect(hwnd, index, &rc); - rc.right -= 1; // 多行TCS_BUTTONS样式下有些标签没有隔开? + on_tabpage_get_padding(hwnd, index, &rc); FrameRect(hdc, &rc, dark_mode ? GetSysColorBrush(COLOR_3DDKSHADOW) : GetSysColorBrush(COLOR_BTNSHADOW)); if (on_tabpage_nfocus(index)) { // 从主题获取COLOR_HIGHLIGHT值 - cr = eu_get_theme()->item.activetab.bgcolor; + cr = !dark_mode ? eu_get_theme()->item.activetab.bgcolor : eu_get_theme()->item.activetab.color; SetBkColor(hdc, cr); ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); } else { - cr = set_btnface_color(hdc, dark_mode); + cr = set_tabface_color(hdc, dark_mode); } if (p->file_attr & FILE_ATTRIBUTE_READONLY) { @@ -389,32 +434,26 @@ on_tabpage_exchange_item(const int old_index, const int new_index, const bool ac { return; } - if (active) + if (old_index > new_index) { - if (old_index > new_index) + for (i = old_index; i > new_index; --i) { - for (i = old_index; i > new_index; --i) - { - SendMessage(g_tabpages, TCM_GETITEM, i - 1, (LPARAM)(&shift_item)); - SendMessage(g_tabpages, TCM_SETITEM, i, (LPARAM)(&shift_item)); - } + SendMessage(g_tabpages, TCM_GETITEM, i - 1, (LPARAM)(&shift_item)); + SendMessage(g_tabpages, TCM_SETITEM, i, (LPARAM)(&shift_item)); } - else + } + else + { + for (i = old_index; i < new_index; ++i) { - for (i = old_index; i < new_index; ++i) - { - SendMessage(g_tabpages, TCM_GETITEM, i + 1, (LPARAM)(&shift_item)); - SendMessage(g_tabpages, TCM_SETITEM, i, (LPARAM)(&shift_item)); - } + SendMessage(g_tabpages, TCM_GETITEM, i + 1, (LPARAM)(&shift_item)); + SendMessage(g_tabpages, TCM_SETITEM, i, (LPARAM)(&shift_item)); } - SendMessage(g_tabpages, TCM_SETITEM, new_index, (LPARAM)(&drag_item)); - on_tabpage_select_index(new_index); } - else + SendMessage(g_tabpages, TCM_SETITEM, new_index, (LPARAM)(&drag_item)); + if (active) { - SendMessage(g_tabpages, TCM_GETITEM, new_index, (LPARAM)(&shift_item)); - SendMessage(g_tabpages, TCM_SETITEM, old_index, (LPARAM)(&shift_item)); - SendMessage(g_tabpages, TCM_SETITEM, new_index, (LPARAM)(&drag_item)); + on_tabpage_select_index(new_index); } } @@ -511,12 +550,12 @@ on_tabpage_send_file(const HWND hwin, const int index) bak.y = eu_int_cast(pos - row + 1); bak.hex = p->hex_mode; } - err = on_file_close(p, FILE_ONLY_CLOSE); + err = on_file_close(&p, FILE_ONLY_CLOSE); } } else { - if (!(err = on_file_close(p, FILE_REMOTE_CLOSE))) + if (!(err = on_file_close(&p, FILE_REMOTE_CLOSE))) { const char *sql = "SELECT * FROM skylark_session;"; err = on_sql_post(sql, on_tabpage_parser_bakup, &bak); @@ -668,7 +707,7 @@ on_tabpage_set_cursor(const int index) POINT point; GetCursorPos(&point); MapWindowPoints(HWND_DESKTOP, g_tabpages, &point, 2); - TabCtrl_GetItemRect(g_tabpages, index, &rc); + on_tabpage_get_padding(g_tabpages, index, &rc); if (!PtInRect(&rc, point)) { int cx = (rc.right - rc.left)/2; @@ -761,7 +800,7 @@ on_tabpage_arr_drag2(const int from, const int dest) } } -LRESULT CALLBACK +static LRESULT CALLBACK on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { int count = 0; @@ -784,8 +823,9 @@ on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) EndPaint(hwnd, &ps); break; } - case WM_SIZE: + case WM_DPICHANGED: { + on_tabpage_adjust_box(NULL); break; } case WM_COMMAND: @@ -821,14 +861,13 @@ on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) g_drag_hcursor ? SetCursor(g_drag_hcursor) : (void *)0; break; } - count = TabCtrl_GetItemCount(hwnd); - for (index = 0; index < count; ++index) + for (index = 0, count = TabCtrl_GetItemCount(hwnd); index < count; ++index) { if (!(p = on_tabpage_get_ptr(index))) { break; } - TabCtrl_GetItemRect(hwnd, index, &rect); + on_tabpage_get_padding(hwnd, index, &rect); if (PtInRect(&rect, point)) { if (!tab_do_drag && tab_drag) @@ -837,7 +876,7 @@ on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) on_tabpage_arr_drag(index); break; } - if (on_tabpage_has_drag(&point) && KEY_DOWN(VK_LBUTTON)) + if (tab_move_from >= 0 && on_tabpage_has_drag(&point) && KEY_DOWN(VK_LBUTTON)) { tab_drag = true; } @@ -867,7 +906,7 @@ on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if ((tab_move_from = on_tabpage_hit_index(&g_point)) != -1) { RECT rc; - TabCtrl_GetItemRect(hwnd, tab_move_from, &rc); + on_tabpage_get_padding(hwnd, tab_move_from, &rc); if (eu_get_config()->m_close_draw != IDM_TABCLOSE_NONE && on_tabpage_hit_button(&rc, &g_point)) { PostMessage(hwnd, WM_MBUTTONUP, 0, lParam); @@ -905,10 +944,12 @@ on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (tab_move_from >= 0) { int count = TabCtrl_GetItemCount(hwnd); + // inter_reserved_1 = 是否锁定标签 if (!PtInRect(&rect, point) && !eu_get_config()->inter_reserved_1) { // Get cursor position of "Screen" GetCursorPos(&point); on_tabpage_drag_mouse(WindowFromPoint(point)); + on_tabpage_variable_reset(); return 1; } if ((index = on_tabpage_hit_index(&point)) != -1) @@ -916,16 +957,15 @@ on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (tab_drag && index != tab_move_from) { on_tabpage_arr_drag2(tab_move_from, index); - break; } - if (tab_mutil_select && !tab_drag) + else if (tab_mutil_select && !tab_drag) { tab_mutil_select = false; on_tabpage_select_index(index); } } - tab_drag = false; } + on_tabpage_variable_reset(); break; } case WM_RBUTTONDOWN: @@ -933,7 +973,7 @@ on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) POINT point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; if ((index = on_tabpage_hit_index(&point)) != -1 && !on_tabpage_nfocus(index)) { - on_tabpage_select_index(index); + on_tabpage_active_one(index); break; } return 1; @@ -955,7 +995,7 @@ on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) POINT point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; if ((index = on_tabpage_hit_index(&point)) != -1 && (p = on_tabpage_get_ptr(index)) != NULL) { - on_file_close(p, FILE_ONLY_CLOSE); + on_file_close(&p, FILE_ONLY_CLOSE); return 1; } break; @@ -964,11 +1004,11 @@ on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (eu_get_config()->m_new_way == IDM_VIEW_TAB_RIGHT_NEW && wParam == MK_RBUTTON) { - on_file_new(); + on_file_new(NULL); } if (eu_get_config()->m_new_way == IDM_VIEW_TAB_DBCLICK_NEW && wParam == MK_LBUTTON) { - on_file_new(); + on_file_new(NULL); } break; } @@ -987,7 +1027,7 @@ on_tabpage_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { break; } - TabCtrl_GetItemRect(hwnd, index, &rect); + on_tabpage_get_padding(hwnd, index, &rect); if (p->at_close) { on_tabpage_flush_close(hwnd, &rect); @@ -1013,7 +1053,8 @@ on_tabpage_create_dlg(HWND hwnd) { int err = 0; const uint32_t flags = \ - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TCS_TOOLTIPS | TCS_BUTTONS | TCS_MULTISELECT | TCS_MULTILINE | TCS_FOCUSNEVER; + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TCS_TOOLTIPS | TCS_BUTTONS | + TCS_MULTISELECT | TCS_MULTILINE | TCS_OWNERDRAWFIXED | TCS_FOCUSNEVER; g_tabpages = CreateWindow(WC_TABCONTROL, NULL, flags, 0, 0, 0, 0, hwnd, (HMENU)IDM_TABPAGE_BAR, eu_module_handle(), NULL); do { @@ -1035,10 +1076,13 @@ on_tabpage_create_dlg(HWND hwnd) err = 1; break; } - SendMessage(g_tabpages, WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0); - TabCtrl_SetPadding(g_tabpages, TAB_MIN_LEFT, TAB_MIN_TOP); - TabCtrl_SetMinTabWidth(g_tabpages, TAB_MIN_WIDTH); - ShowWindow(g_tabpages, SW_SHOW); + if (true) + { + TabCtrl_SetPadding(g_tabpages, TAB_MIN_LEFT, 0); + TabCtrl_SetMinTabWidth(g_tabpages, TAB_MIN_WIDTH); + on_theme_update_font(tabbar_id); + util_tab_height(g_tabpages, TAB_MIN_WIDTH); + } if (!(old_tabproc = (WNDPROC) SetWindowLongPtr(g_tabpages, GWLP_WNDPROC, (LONG_PTR) on_tabpage_proc_callback))) { err = 1; @@ -1056,7 +1100,8 @@ on_tabpage_create_dlg(HWND hwnd) void on_tabpage_close_tabs(int it) { - on_file_close(on_tabpage_get_ptr(it), FILE_ONLY_CLOSE); + eu_tabpage *p = on_tabpage_get_ptr(it); + on_file_close(&p, FILE_ONLY_CLOSE); } void @@ -1088,47 +1133,65 @@ on_tabpage_do_file(tab_callback func) cvector_freep(&v); } +void +on_tabpage_size(void) +{ + if (g_tabpages) + { + RECT rc_tabbar; + on_tabpage_adjust_box(&rc_tabbar); + MoveWindow(g_tabpages, rc_tabbar.left, rc_tabbar.top, rc_tabbar.right - rc_tabbar.left, rc_tabbar.bottom - rc_tabbar.top, TRUE); + ShowWindow(g_tabpages, SW_SHOW); + } +} + void on_tabpage_adjust_box(RECT *ptp) { - RECT rect_main; - RECT rect_treebar = { 0 }; - int tab_height = on_tabpage_internal_height(); - int row = TabCtrl_GetRowCount(g_tabpages); - tab_height += row > 1 ? 3 * (row - 1) : 0; - GetClientRect(eu_module_hwnd(), &rect_main); - if (!eu_get_config()->m_ftree_show) + if (ptp) { - ptp->left = rect_main.left; + RECT rc_main; + RECT rc_treebar = { 0 }; + on_treebar_adjust_box(&rc_treebar, &rc_main); + if (!eu_get_config()->m_ftree_show) + { + ptp->left = rc_main.left; + } + else + { + ptp->left = rc_treebar.right; + } + ptp->right = rc_main.right; + ptp->top = rc_treebar.top; + ptp->bottom = rc_treebar.bottom; } - else + else if (g_tabpages) { - on_treebar_adjust_box(&rect_treebar); - ptp->left = rect_treebar.right; + util_tab_height(g_tabpages, TAB_MIN_WIDTH); } - ptp->top = rect_main.top + on_toolbar_height(); - ptp->right = rect_main.right; - ptp->bottom = ptp->top + tab_height + SCINTILLA_MARGIN_TOP; } void -on_tabpage_adjust_window(eu_tabpage *pnode) +on_tabpage_adjust_window(eu_tabpage *pnode, RECT *ptab) { - int tab_height = 0; - RECT rect_tabpages = {0}; + RECT rc_tabpages = {0}; + if (!ptab) + { + ptab = &rc_tabpages; + } if (true) { - RECT rect_main; - GetClientRect(eu_module_hwnd(), &rect_main); - on_tabpage_adjust_box(&rect_tabpages); - pnode->rect_sc.left = rect_tabpages.left; + RECT rc_main; + GetClientRect(eu_module_hwnd(), &rc_main); + on_tabpage_adjust_box(ptab); + pnode->rect_sc.left = ptab->left; if (eu_get_config()->m_ftree_show) { pnode->rect_sc.left += SPLIT_WIDTH; } - pnode->rect_sc.right = rect_tabpages.right; - pnode->rect_sc.top = rect_tabpages.bottom; - pnode->rect_sc.bottom = rect_main.bottom - on_statusbar_height(); + pnode->rect_sc.right = ptab->right; + pnode->rect_sc.top = ptab->top + on_tabpage_get_height(); + pnode->rect_sc.bottom = ptab->bottom; } if (pnode->sym_show) { @@ -1137,7 +1200,7 @@ on_tabpage_adjust_window(eu_tabpage *pnode) pnode->rect_sc.right -= (pnode->hwnd_symlist ? eu_get_config()->sym_list_width : eu_get_config()->sym_tree_width) + SPLIT_WIDTH; pnode->rect_sym.left = pnode->rect_sc.right + SPLIT_WIDTH; - pnode->rect_sym.right = rect_tabpages.right; + pnode->rect_sym.right = ptab->right; pnode->rect_sym.top = pnode->rect_sc.top; pnode->rect_sym.bottom = pnode->rect_sc.bottom; } @@ -1148,7 +1211,7 @@ on_tabpage_adjust_window(eu_tabpage *pnode) { pnode->rect_sc.right -= eu_get_config()->document_map_width + SPLIT_WIDTH; pnode->rect_map.left = pnode->rect_sc.right + SPLIT_WIDTH; - pnode->rect_map.right = rect_tabpages.right; + pnode->rect_map.right = ptab->right; pnode->rect_map.top = pnode->rect_sc.top; pnode->rect_map.bottom = pnode->rect_sc.bottom; } @@ -1172,21 +1235,25 @@ on_tabpage_adjust_window(eu_tabpage *pnode) } } -int -on_tabpage_remove(eu_tabpage **ppnode) +eu_tabpage * +on_tabpage_remove(const eu_tabpage *pnode, const CLOSE_MODE mode) { eu_tabpage *p = NULL; - EU_VERIFY(ppnode != NULL && *ppnode != NULL && g_tabpages != NULL); + EU_VERIFY(pnode != NULL && g_tabpages != NULL); for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { - if ((p = on_tabpage_get_ptr(index)) && p == *ppnode) - { /* 删除控件句柄与释放资源 */ + if ((p = on_tabpage_get_ptr(index)) && p == pnode) + { /* 从控件删除选项卡 */ + p->tab_id = index; TabCtrl_DeleteItem(g_tabpages, index); - on_sci_free_tab(ppnode); - return index; + if (file_click_close(mode) && count < 2 && !TAB_HEX_MODE(pnode) && !pnode->plugin) + { + p->reason = TABS_MAYBE_RESERVE; + } + return p; } } - return EUE_TAB_NULL; + return NULL; } static int @@ -1216,7 +1283,7 @@ on_tabpage_replace_empty(eu_tabpage *pre) } TCHAR * -on_tabpage_generator(TCHAR *filename, int len) +on_tabpage_generator(TCHAR *filename, const int len) { EU_VERIFY(g_tabpages != NULL); LOAD_I18N_RESSTR(IDC_MSG_NEW_FILE, m_file); @@ -1306,7 +1373,7 @@ int on_tabpage_add(eu_tabpage *pnode) { EU_VERIFY(pnode != NULL && g_tabpages != NULL); - if (TAB_NOT_BIN(pnode) && !pnode->hex_mode && !pnode->pmod) + if (TAB_NOT_BIN(pnode) && !TAB_HEX_MODE(pnode) && !pnode->pmod) { pnode->doc_ptr = on_doc_get_type(pnode->filename); } @@ -1330,9 +1397,10 @@ on_tabpage_add(eu_tabpage *pnode) { eu_logmsg("%s: Replacing empty Tab, pnode->tab_id = %d\n", __FUNCTION__, pnode->tab_id); } - if ((pnode->fs_server.networkaddr[0] == 0 || pnode->bakpath[0]) && pnode->hex_mode) + if ((pnode->fs_server.networkaddr[0] == 0 || pnode->bakpath[0]) && TAB_HEX_MODE(pnode)) { pnode->bytes_remaining = (size_t)pnode->raw_size; + eu_logmsg("%s: hexview_init execute\n", __FUNCTION__); if (!hexview_init(pnode)) { TabCtrl_DeleteItem(g_tabpages, pnode->tab_id); @@ -1364,7 +1432,7 @@ int on_tabpage_reload_file(eu_tabpage *pnode, int flags, sptr_t *pline) { EU_VERIFY(pnode != NULL); - if (pnode->hex_mode || pnode->plugin) + if (TAB_HEX_MODE(pnode) || pnode->plugin) { return 0; } @@ -1377,7 +1445,7 @@ on_tabpage_reload_file(eu_tabpage *pnode, int flags, sptr_t *pline) case 1: // 丢弃 pnode->be_modify = false; pnode->fn_modify = false; - on_file_close(pnode, FILE_ONLY_CLOSE); + on_file_close(&pnode, FILE_ONLY_CLOSE); break; case 2: // 重载, 滚动到末尾行 { @@ -1424,13 +1492,13 @@ on_tabpage_theme_changed(eu_tabpage *p) { if (p && p->hwnd_sc) { - PostMessage(p->hwnd_sc, WM_THEMECHANGED, 0, 0); + SendMessage(p->hwnd_sc, WM_THEMECHANGED, 0, 0); } if (p->sym_show) { if (p->hwnd_symlist) { - PostMessage(p->hwnd_symlist, WM_THEMECHANGED, 0, 0); + SendMessage(p->hwnd_symlist, WM_THEMECHANGED, 0, 0); } else if (p->hwnd_symtree) { @@ -1452,14 +1520,17 @@ on_tabpage_theme_changed(eu_tabpage *p) } bool -on_tabpage_check_map(void) +on_tabpage_exist_map(void) { - for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) + if (g_tabpages) { - eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && p->map_show) + eu_tabpage *p = NULL; + for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { - return true; + if ((p = on_tabpage_get_ptr(index)) && p->map_show) + { + return true; + } } } return false; @@ -1479,7 +1550,7 @@ on_tabpage_foreach(tab_ptr fntab) } eu_tabpage * -on_tabpage_get_ptr(int index) +on_tabpage_get_ptr(const int index) { TCITEM tci = {TCIF_PARAM}; if (TabCtrl_GetItem(g_tabpages, index, &tci)) @@ -1500,7 +1571,7 @@ on_tabpage_selection(eu_tabpage *pnode, int index) { EU_VERIFY(pnode != NULL && g_tabpages != NULL); eu_tabpage *p = NULL; - int count = TabCtrl_GetItemCount(g_tabpages); + const int count = TabCtrl_GetItemCount(g_tabpages); if (index < 0) { for (index = 0; index < count; ++index) @@ -1516,7 +1587,7 @@ on_tabpage_selection(eu_tabpage *pnode, int index) { HWND hwnd = eu_module_hwnd(); on_tabpage_set_active(index); - on_proc_resize(hwnd); + eu_window_resize(hwnd); if ((p = on_tabpage_get_ptr(index))) { // 窗口处理过程中可能改变了标签位置, 重置它 on_tabpage_deselect(index); @@ -1547,7 +1618,7 @@ on_tabpage_get_handle(void *hwnd_sc) } int -on_tabpage_get_index(eu_tabpage *pnode) +on_tabpage_get_index(const eu_tabpage *pnode) { if (g_tabpages) { diff --git a/src/eu_tabpage.h b/src/eu_tabpage.h index d06d47e0..b4578d45 100644 --- a/src/eu_tabpage.h +++ b/src/eu_tabpage.h @@ -20,7 +20,10 @@ #define _H_SKYLARK_TABPAGES_ #define CONFIG_KEY_MATERIAL_TABPAGES "EU_TABPAG" -#define TABS_HEIGHT_DEFAULT 23 +#define TABS_WIDTH_DEFAULT (120) +#define TABS_HEIGHT_DEFAULT (23) +#define TABS_MAYBE_RESERVE (-1) +#define TABS_MAYBE_EIXT (-2) #ifdef __cplusplus extern "C" @@ -52,13 +55,12 @@ struct _tabpage bool result_show; // 是否显示文档搜索结果窗口 bool sidebar_show; // 是否显示侧边栏窗口 bool foldline; // 是否存在折叠线 - bool needpre; // 是否需要bom + bool needpre; // 是否需要bom bool is_blank; // 新建文件,空白标签 - bool at_close; // 是否绘制了关闭按钮 - bool hex_mode; // 是否处于16禁止编辑状态 + bool at_close; // 是否绘制了关闭按钮 bool be_modify; // 文档是否修改, 同步hex模式 bool fn_modify; // 文档打开时的初始状态 - bool last_focus; // 保存前台焦点 + bool last_focus; // 保存前台焦点 TCHAR pathfile[MAX_BUFFER]; // 文件带路径名 TCHAR pathname[MAX_BUFFER]; // 文件所在路径名 TCHAR bakpath[MAX_BUFFER]; // 备份后的名称 @@ -69,7 +71,7 @@ struct _tabpage char icon_undo_str[QW_SIZE];// 编码转换时保存的数据,用于undo操作 size_t pre_len; // bom的长度 size_t bytes_remaining; // 文件变动后的大小 - size_t bytes_written; // 文件保存时写入的长度 + size_t bytes_written; // 文件保存时写入的长度 time_t st_mtime; // 文件修改时间 uint32_t file_attr; // 文件属性,只读/可写... intptr_t match_count; // 查找时匹配计数 @@ -83,17 +85,22 @@ struct _tabpage volatile long busy_id; // 标签是否空闲状态 volatile long lock_id; // 自动保存时使用的锁 int tab_id; // tab编号,用于保存会话 - int codepage; // 文件编码 + int hex_mode; // 16进制编辑状态, 0, 否. 1,是. 2,插件 + int codepage; // 真实的文件编码 + int bakcp; // 自动保存时的文件编码 int eol; // 换行符 int zoom_level; // 标签页的放大倍数 int ac_mode; // 是否处于snippet模式 + int reason; // 编辑器窗口状态 + int initial; // 标签初始化状态 + int view; // 标签所在视图 remotefs fs_server; // SFTP PHEXVIEW phex; // 二进制视图 uint8_t *write_buffer; // 文件保存时写入的缓存区 eu_tabpage *presult; // 文档搜索结果的节点指针 doctype_t *doc_ptr; // 文件类型指针 db_conn *db_ptr; // 数据库配置 - redis_conn *redis_ptr; // redis配置 + redis_conn *redis_ptr; // redis配置 result_vec *ret_vec; // 搜索结果标记 complete_ptr ac_vec; // snippet模式下的vec数组 capture_ptr re_group; // snippet正则模式下捕获组 @@ -106,17 +113,16 @@ extern HWND g_tabpages; int on_tabpage_create_dlg(HWND hwnd); int on_tabpage_add(eu_tabpage *pnode); -int on_tabpage_remove(eu_tabpage **ppnode); int on_tabpage_reload_file(eu_tabpage *pnode, int flags, sptr_t *pline); int on_tabpage_theme_changed(eu_tabpage *p); int on_tabpage_get_height(void); -int on_tabpage_get_index(eu_tabpage *pnode); +int on_tabpage_get_index(const eu_tabpage *pnode); int on_tabpage_selection(eu_tabpage *pnode, int index); int on_tabpage_sel_number(int **pvec, const bool ascending); int on_tabpage_sel_path(wchar_t ***pvec, bool *hex); void on_tabpage_switch_next(HWND hwnd); void on_tabpage_adjust_box(RECT *ptp); -void on_tabpage_adjust_window(eu_tabpage *pnode); +void on_tabpage_adjust_window(eu_tabpage *pnode, RECT *ptab); void on_tabpage_set_title(int ntab, TCHAR *title); void on_tabpage_symlist_click(eu_tabpage *pnode); void on_tabpage_foreach(tab_ptr fntab); @@ -127,12 +133,15 @@ void on_tabpage_push_editor(int); void on_tabpage_do_file(tab_callback func); void on_tabpage_active_tab(eu_tabpage *pnode); void on_tabpage_active_one(int index); -bool on_tabpage_check_map(void); +void on_tabpage_size(void); +void on_tabpage_variable_reset(void); +bool on_tabpage_exist_map(void); eu_tabpage *on_tabpage_get_handle(void *hwnd_sc); -eu_tabpage *on_tabpage_get_ptr(int index); +eu_tabpage *on_tabpage_get_ptr(const int index); eu_tabpage *on_tabpage_select_index(int index); eu_tabpage *on_tabpage_focus_at(void); -TCHAR *on_tabpage_generator(TCHAR *filename, int len); +eu_tabpage *on_tabpage_remove(const eu_tabpage *pnode, const CLOSE_MODE mode); +TCHAR *on_tabpage_generator(TCHAR *filename, const int len); LRESULT on_tabpage_draw_item(HWND hwnd, WPARAM wParam, LPARAM lParam); #ifdef __cplusplus diff --git a/src/eu_theme.c b/src/eu_theme.c index 41b8a0d9..ef5c3d6d 100644 --- a/src/eu_theme.c +++ b/src/eu_theme.c @@ -18,6 +18,8 @@ #include "framework.h" #include +#define FONT_DEFAULT_SIZE (-12) + static HFONT g_hfont; static HWND hwnd_edit_tips; static HBRUSH brush_linenumber; @@ -267,6 +269,58 @@ on_theme_update_item(void) } } +void +on_theme_update_font(const control_id id) +{ + switch (id) + { + case all_id: + if (g_tabpages) + { + SendMessage(g_tabpages, WM_SETFONT, (WPARAM)g_hfont, 0); + } + if (g_treebar) + { + SendMessage(g_treebar, WM_SETFONT, (WPARAM)g_hfont, 0); + } + if (g_filetree) + { + SendMessage(g_filetree, WM_SETFONT, (WPARAM)g_hfont, 0); + } + if (g_statusbar) + { + SendMessage(GetDlgItem(g_statusbar, IDM_BTN_RW), WM_SETFONT, (WPARAM)g_hfont, 0); + } + break; + case tabbar_id: + if (g_tabpages) + { + SendMessage(g_tabpages, WM_SETFONT, (WPARAM)g_hfont, 0); + } + break; + case filebar_id: + if (g_treebar) + { + SendMessage(g_treebar, WM_SETFONT, (WPARAM)g_hfont, 0); + } + break; + case filetree_id: + if (g_filetree) + { + SendMessage(g_filetree, WM_SETFONT, (WPARAM)g_hfont, 0); + } + break; + case btn_id: + if (g_statusbar) + { + SendMessage(GetDlgItem(g_statusbar, IDM_BTN_RW), WM_SETFONT, (WPARAM)g_hfont, 0); + } + break; + default: + break; + } +} + HFONT on_theme_font_hwnd(void) { @@ -276,19 +330,25 @@ on_theme_font_hwnd(void) bool on_theme_setup_font(HWND hwnd) { - if (g_hfont) - { - DeleteObject(g_hfont); - } NONCLIENTMETRICS ncm = {sizeof(NONCLIENTMETRICS)}; SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0); LOGFONT logfont = ncm.lfMessageFont; - int font_size = logfont.lfHeight < 0 ? -logfont.lfHeight : logfont.lfHeight; - logfont.lfHeight = -MulDiv(font_size, eu_get_dpi(hwnd), USER_DEFAULT_SCREEN_DPI); - g_hfont = CreateFontIndirect(&logfont); + if (util_under_wine()) + { // 跟windows不同, wine预先对字体进行了缩放 + util_make_u16(eu_get_theme()->item.text.font, logfont.lfFaceName, _countof(logfont.lfFaceName) - 1); + } + else + { // 在windows下, 因为10与11的差别, 使用标准字体大小 + logfont.lfHeight = -MulDiv(-FONT_DEFAULT_SIZE, eu_get_dpi(hwnd), USER_DEFAULT_SCREEN_DPI); + } if (g_hfont) + { + DeleteObject(g_hfont); + } + if ((g_hfont = CreateFontIndirect(&logfont))) { SendMessage(hwnd, WM_SETFONT, (WPARAM) g_hfont, 0); + on_theme_update_font(all_id); } return (g_hfont != NULL); } @@ -472,7 +532,7 @@ choose_style_font(char *font, int *fontsize, int *bold) } static int -choose_text_color(HWND hwnd, uint32_t *color) +choose_style_color(HWND hwnd, uint32_t *color) { COLORREF cr = {0}; COLORREF crs[16]; @@ -580,7 +640,7 @@ choose_text_color(HWND hwnd, uint32_t *color) } \ else if (wm_id == _idc_settextcolor_button_) \ { \ - choose_text_color(hdlg, &(dlg_style._st_memb_.color)); \ + choose_style_color(hdlg, &(dlg_style._st_memb_.color)); \ InvalidateRect(_hwnd_handle_name_, NULL, TRUE); \ } @@ -662,7 +722,7 @@ theme_show_balloon_tip(const HWND hdlg, const int resid) hwnd_edit_tips = util_create_tips(hwnd_edit, hdlg, ptxt); if (hwnd_edit_tips && on_dark_enable()) { - on_dark_set_theme(hwnd_edit_tips, L"DarkMode_Explorer", NULL); + on_dark_set_theme(hwnd_edit_tips, DARKMODE, NULL); } } } @@ -938,14 +998,15 @@ theme_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) } else if ((HWND) lParam == hwnd_activetab_static) { - dlg_style.activetab.bgcolor &= 0x00ffffff; + const bool dark = on_dark_enable(); + colour cr = !dark ? (dlg_style.activetab.bgcolor &= 0x00ffffff) : (dlg_style.activetab.color &= 0x00ffffff); SetTextColor((HDC) wParam, dlg_style.text.color); - SetBkColor((HDC) wParam, dlg_style.activetab.bgcolor); + SetBkColor((HDC) wParam, cr); if (brush_activetab) { DeleteObject(brush_activetab); } - brush_activetab = CreateSolidBrush(dlg_style.activetab.bgcolor); + brush_activetab = CreateSolidBrush(cr); return (INT_PTR) brush_activetab; } else if ((HWND) lParam == hwnd_result_lineno_static) @@ -1030,7 +1091,13 @@ theme_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (hwnd_caret) { Edit_GetText(hwnd_caret, alpha, 4); - value = _tstoi(alpha) << 24 & 0xff000000; + value = _tstoi(alpha); + if (value < 1 || value > 9) + { + value = 2; + } + value = value << 24 & 0xff000000; + dlg_style.caret.color &= 0x00ffffff; dlg_style.caret.color |= value; } memcpy(&(eu_get_theme()->item), &dlg_style, sizeof(struct styletheme)); @@ -1053,15 +1120,15 @@ theme_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; } case IDC_SETTEXTCOLOR_LINENUMBER_BTN: - choose_text_color(hdlg, &(dlg_style.linenumber.color)); + choose_style_color(hdlg, &(dlg_style.linenumber.color)); InvalidateRect(hwnd_linenumber_static, NULL, TRUE); break; case IDC_SETBGCOLOR_LINENUMBER_BTN: - choose_text_color(hdlg, &(dlg_style.linenumber.bgcolor)); + choose_style_color(hdlg, &(dlg_style.linenumber.bgcolor)); InvalidateRect(hwnd_linenumber_static, NULL, TRUE); break; case IDC_SETBGCOLOR_FOLDMARGIN_BTN: - choose_text_color(hdlg, &(dlg_style.foldmargin.bgcolor)); + choose_style_color(hdlg, &(dlg_style.foldmargin.bgcolor)); InvalidateRect(hwnd_foldmargin_static, NULL, TRUE); break; case IDC_SETFONT_TEXT_BTN: @@ -1094,74 +1161,74 @@ theme_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; } case IDC_SETTEXTCOLOR_TEXT_BTN: - choose_text_color(hdlg, &(dlg_style.text.color)); + choose_style_color(hdlg, &(dlg_style.text.color)); InvalidateRect(hwnd_text_static, NULL, TRUE); break; case IDC_SETBGCOLOR_TEXT_BTN: - choose_text_color(hdlg, &(dlg_style.text.bgcolor)); + choose_style_color(hdlg, &(dlg_style.text.bgcolor)); InvalidateRect(hwnd_text_static, NULL, TRUE); break; case IDC_SETBGCOLOR_CARETLINE_BTN: - choose_text_color(hdlg, &(dlg_style.caretline.bgcolor)); + choose_style_color(hdlg, &(dlg_style.caretline.bgcolor)); InvalidateRect(hwnd_caretline_static, NULL, TRUE); break; case IDC_SETBGCOLOR_INDICATOR_BTN: { - choose_text_color(hdlg, &dlg_style.indicator.bgcolor); + choose_style_color(hdlg, &dlg_style.indicator.bgcolor); InvalidateRect(hwnd_indicator_static, NULL, TRUE); break; } case IDC_SETBGCOLOR_TAB_BTN: { - choose_text_color(hdlg, &dlg_style.activetab.bgcolor); + choose_style_color(hdlg, !on_dark_enable() ? &dlg_style.activetab.bgcolor : &dlg_style.activetab.color); InvalidateRect(hwnd_activetab_static, NULL, TRUE); break; } case IDC_SETCOLOR_CARET_BTN: { - choose_text_color(hdlg, &(dlg_style.caret.color)); + choose_style_color(hdlg, &(dlg_style.caret.color)); InvalidateRect(hwnd_caret_static, NULL, TRUE); break; } case IDC_SETTEXTCOLOR_LINENO_BTN: { - choose_text_color(hdlg, &dlg_style.results.color); + choose_style_color(hdlg, &dlg_style.results.color); InvalidateRect(hwnd_result_lineno_static, NULL, FALSE); break; } case IDC_SETTEXTCOLOR_LINEKEY_BTN: { - choose_text_color(hdlg, &(dlg_style.results.bgcolor)); + choose_style_color(hdlg, &(dlg_style.results.bgcolor)); InvalidateRect(hwnd_result_key_static, NULL, FALSE); break; } case IDC_SETTEXTCOLORBRACESECTION_BTN: { - choose_text_color(hdlg, &dlg_style.bracesection.color); + choose_style_color(hdlg, &dlg_style.bracesection.color); InvalidateRect(hwnd_bracesection_static, NULL, FALSE); break; } case IDC_SETTEXTCOLOR_HISTORY_BTN: { - choose_text_color(hdlg, &dlg_style.nchistory.color); + choose_style_color(hdlg, &dlg_style.nchistory.color); InvalidateRect(hwnd_nchistory_static, NULL, FALSE); break; } case IDC_SETTEXTCOLOR_HISTORY2_BTN: { - choose_text_color(hdlg, &(dlg_style.nchistory.bgcolor)); + choose_style_color(hdlg, &(dlg_style.nchistory.bgcolor)); InvalidateRect(hwnd_nchistory_static2, NULL, FALSE); break; } case IDC_SETTEXTCOLOR_HISTORYDOC_BTN: { - choose_text_color(hdlg, &dlg_style.dochistory.color); + choose_style_color(hdlg, &dlg_style.dochistory.color); InvalidateRect(hwnd_dochistory_static, NULL, FALSE); break; } case IDC_SETTEXTCOLOR_HISTORYDOC2_BTN: { - choose_text_color(hdlg, &(dlg_style.dochistory.bgcolor)); + choose_style_color(hdlg, &(dlg_style.dochistory.bgcolor)); InvalidateRect(hwnd_dochistory_static2, NULL, FALSE); break; } diff --git a/src/eu_theme.h b/src/eu_theme.h index 13f441b1..766ccf8f 100644 --- a/src/eu_theme.h +++ b/src/eu_theme.h @@ -32,6 +32,15 @@ typedef struct _theme_query TCHAR name[QW_SIZE]; }theme_query; +typedef enum _control_id +{ + all_id = 0, + tabbar_id, + filebar_id, + filetree_id, + btn_id +} control_id; + #ifdef __cplusplus extern "C" { #endif @@ -42,6 +51,7 @@ HFONT on_theme_font_hwnd(void); int on_theme_copy_style(TCHAR *ac_theme); int on_theme_load_script(const TCHAR *name); void on_theme_update_item(void); +void on_theme_update_font(const control_id id); bool on_theme_setup_font(HWND hwnd); bool on_theme_create_dlg(void); diff --git a/src/eu_theme_dark.c b/src/eu_theme_dark.c index e5ff787a..b4d85802 100644 --- a/src/eu_theme_dark.c +++ b/src/eu_theme_dark.c @@ -41,12 +41,13 @@ static OpenNcThemeDataPtr fnOpenNcThemeData; static ShouldSystemUseDarkModePtr fnShouldSystemUseDarkMode; static SetPreferredAppModePtr fnSetPreferredAppMode; -static bool g_dark_supported; -static bool g_dark_enabled; -static HMODULE g_uxtheme; -static HBRUSH g_dark_bkgnd; -static HBRUSH g_dark_hot_bkgnd; -static HBRUSH g_theme_bkgnd; +static bool g_dark_supported = false; +static bool g_dark_enabled = false; +static bool g_color_enable = false; +static HMODULE g_uxtheme = NULL; +static HBRUSH g_dark_bkgnd = NULL; +static HBRUSH g_dark_hot_bkgnd = NULL; +static HBRUSH g_theme_bkgnd = NULL; bool on_dark_supports(void) @@ -75,7 +76,7 @@ on_dark_high_contrast(void) bool on_dark_enable(void) { - return g_dark_enabled && on_dark_apps_use() && !on_dark_high_contrast(); + return g_dark_enabled && (eu_win11_or_later() ? true : on_dark_apps_use()) && !on_dark_high_contrast(); } HRESULT @@ -181,27 +182,31 @@ on_dark_set_theme(HWND hwnd, const wchar_t *psz_name, const wchar_t *psz_list) void on_dark_set_titlebar(HWND hwnd, BOOL dark) { - if (eu_win10_or_later() < 18362) + const uint32_t number = eu_win10_or_later(); + if (number != (uint32_t)-1) { - #if USE_DWMAPI - HMODULE dwm = np_load_plugin_library(_T("dwmapi.dll"), true); - DwmSetWindowAttributePtr fnDwmSetWindowAttribute = dwm ? (DwmSetWindowAttributePtr)GetProcAddress(dwm, "DwmSetWindowAttribute") : NULL; - if (fnDwmSetWindowAttribute) + if (number < 18362) { - if (S_OK != fnDwmSetWindowAttribute(hwnd, 20, &dark, sizeof dark)) - { // this would be the call before Windows build 18362 - fnDwmSetWindowAttribute(hwnd, 19, &dark, sizeof dark); + #if USE_DWMAPI + HMODULE dwm = np_load_plugin_library(_T("dwmapi.dll"), true); + DwmSetWindowAttributePtr fnDwmSetWindowAttribute = dwm ? (DwmSetWindowAttributePtr)GetProcAddress(dwm, "DwmSetWindowAttribute") : NULL; + if (fnDwmSetWindowAttribute) + { + if (S_OK != fnDwmSetWindowAttribute(hwnd, 20, &dark, sizeof dark)) + { // this would be the call before Windows build 18362 + fnDwmSetWindowAttribute(hwnd, 19, &dark, sizeof dark); + } } + eu_close_dll(dwm); + #else + SetProp(hwnd, _T("UseImmersiveDarkModeColors"), (HANDLE)(intptr_t)(dark)); + #endif // USE_DWMAPI + } + else if (fnSetWindowCompositionAttribute) // number < 22000 && + { + WINDOWCOMPOSITIONATTRIBDATA data = {WCA_USEDARKMODECOLORS, &dark, sizeof(dark)}; + fnSetWindowCompositionAttribute(hwnd, &data); } - eu_close_dll(dwm); - #else - SetProp(hwnd, _T("UseImmersiveDarkModeColors"), (HANDLE)(intptr_t)(dark)); - #endif // USE_DWMAPI - } - else if (fnSetWindowCompositionAttribute) - { - WINDOWCOMPOSITIONATTRIBDATA data = {WCA_USEDARKMODECOLORS, &dark, sizeof(dark)}; - fnSetWindowCompositionAttribute(hwnd, &data); } } @@ -218,17 +223,22 @@ on_dark_set_caption(void) const uint32_t number = eu_win10_or_later(); if ((ret = number != (uint32_t)-1) && number >= 22000) { - #if USE_DWMAPI - HMODULE dwm = np_load_plugin_library(_T("dwmapi.dll"), true); - DwmSetWindowAttributePtr fnDwmSetWindowAttribute = dwm ? (DwmSetWindowAttributePtr)GetProcAddress(dwm, "DwmSetWindowAttribute") : NULL; - if ((ret = fnDwmSetWindowAttribute != NULL)) + const bool white = eu_theme_index() == THEME_WHITE; + if (!(white && g_color_enable)) { - colour mycolor = eu_theme_index() == THEME_WHITE ? rgb_dark_txt_color : DWMWA_COLOR_DEFAULT; - ret = S_OK == fnDwmSetWindowAttribute(eu_module_hwnd(), DWMWA_CAPTION_COLOR, &mycolor, sizeof mycolor); - eu_logmsg("%s: ret = %d\n", __FUNCTION__, ret); + #if USE_DWMAPI + HMODULE dwm = np_load_plugin_library(_T("dwmapi.dll"), true); + DwmSetWindowAttributePtr fnDwmSetWindowAttribute = dwm ? (DwmSetWindowAttributePtr)GetProcAddress(dwm, "DwmSetWindowAttribute") : NULL; + if ((ret = fnDwmSetWindowAttribute != NULL)) + { + colour mycolor = white ? rgb_dark_txt_color : DWMWA_COLOR_DEFAULT; + ret = S_OK == fnDwmSetWindowAttribute(eu_module_hwnd(), DWMWA_CAPTION_COLOR, &mycolor, sizeof mycolor); + g_color_enable = white && ret == S_OK; + eu_logmsg("%s: ret = %d\n", __FUNCTION__, ret); + } + eu_close_dll(dwm); + #endif // USE_DWMAPI } - eu_close_dll(dwm); - #endif // USE_DWMAPI } return ret; } @@ -271,12 +281,15 @@ bool on_dark_color_scheme_change(LPARAM lParam) { bool is = false; - if (lParam && (0 == _tcsicmp((const TCHAR *)lParam, _T("ImmersiveColorSet")))) + if (lParam && (0 == _tcsicmp((const TCHAR *)lParam, _T("ImmersiveColorSet"))) && fnRefreshImmersiveColorPolicyState) { fnRefreshImmersiveColorPolicyState(); is = true; } - fnGetIsImmersiveColorUsingHighContrast(IHCM_REFRESH); + if (fnGetIsImmersiveColorUsingHighContrast) + { + fnGetIsImmersiveColorUsingHighContrast(IHCM_REFRESH); + } return is; } @@ -365,9 +378,7 @@ on_dark_get_bgbrush(void) { // not dark mode if (on_dark_set_caption()) { - g_dark_bkgnd = eu_theme_index() == THEME_WHITE ? - GetSysColorBrush(COLOR_WINDOW) : - GetSysColorBrush(COLOR_MENU); + g_dark_bkgnd = eu_theme_index() == THEME_WHITE && !util_under_wine() ? GetSysColorBrush(COLOR_WINDOW) : GetSysColorBrush(COLOR_MENU); } else { @@ -495,7 +506,7 @@ on_dark_tips_theme(HWND hwnd, int msg) HWND htips = (HWND) SendMessage(hwnd, msg, 0, 0); if (NULL != htips) { - on_dark_set_theme(htips, g_dark_enabled ? L"DarkMode_Explorer" : NULL, NULL); + on_dark_set_theme(htips, g_dark_enabled ? DARKMODE : NULL, NULL); } } } @@ -510,30 +521,11 @@ eu_dark_theme_release(bool shutdown) } else if (g_dark_enabled) { - HWND hwnd = eu_module_hwnd(); - on_dark_set_titlebar(hwnd, false); on_dark_allow_app(false); - on_dark_allow_window(hwnd, false); - on_statusbar_dark_release(true); g_dark_enabled = false; - on_toolbar_refresh(hwnd); fnFlushMenuThemes(); eu_close_dll(g_uxtheme); SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_NORMAL, 10, 0); - on_dark_tips_theme(g_tabpages, TCM_GETTOOLTIPS); - on_tabpage_foreach(on_tabpage_theme_changed); - if (g_treebar) - { - SendMessage(g_treebar, WM_THEMECHANGED, 0, 0); - } - if (g_filetree) - { - SendMessage(g_filetree, WM_THEMECHANGED, 0, 0); - } - if (g_tabpages) - { - SendMessage(g_tabpages, WM_THEMECHANGED, 0, 0); - } on_dark_delete_brush(); on_theme_menu_release(); } @@ -595,12 +587,15 @@ eu_dark_theme_init(bool fix_scroll, bool dark) } if (g_dark_enabled && on_dark_create_hot_brush() && on_dark_set_caption()) { + eu_logmsg("dark theme is successfully initialized\n"); return on_dark_create_bgbrush(); } else { g_dark_supported = false; + g_dark_enabled = false; eu_close_dll(g_uxtheme); + eu_logmsg("dark theme initialization failed\n"); } } } diff --git a/src/eu_theme_dark.h b/src/eu_theme_dark.h index 0694ff7f..7bc97389 100644 --- a/src/eu_theme_dark.h +++ b/src/eu_theme_dark.h @@ -99,6 +99,8 @@ typedef HRESULT (WINAPI *DwmGetColorizationColorPtr)(DWORD *pcrColorization, BOO #define UpdateWindowEx(hwnd) \ RedrawWindow((hwnd), NULL, NULL, RDW_ERASE|RDW_FRAME|RDW_INVALIDATE|RDW_INTERNALPAINT) \ +#define DARKMODE (_T("DarkMode_Explorer")) + #define rgb_alpha(rgb, a) \ ((int)(((colour)((rgb)&0xffffff)) | (((colour)(uint8_t)((a)&0xff)) << 24))) \ @@ -147,7 +149,13 @@ intptr_t on_dark_theme_brush(void); static inline uint32_t set_bk_color(const HDC hdc, const bool use_dark) { - return use_dark ? SetBkColor(hdc, rgb_dark_bk_color) : SetBkColor(hdc, GetSysColor(COLOR_WINDOW)); + return use_dark ? SetBkColor(hdc, eu_win11_or_later() ? rgb_dark_bk11_color : rgb_dark_bk_color) : SetBkColor(hdc, GetSysColor(COLOR_WINDOW)); +} + +static inline uint32_t +set_tabface_color(const HDC hdc, const bool use_dark) +{ + return use_dark ? SetBkColor(hdc, eu_win11_or_later() ? rgb_dark_bk11_color : rgb_dark_bk_color) : SetBkColor(hdc, GetSysColor(COLOR_BTNFACE)); } static inline uint32_t diff --git a/src/eu_toolbar.c b/src/eu_toolbar.c index 366551fd..a2d3edfa 100644 --- a/src/eu_toolbar.c +++ b/src/eu_toolbar.c @@ -21,6 +21,7 @@ #include "framework.h" #define DPI_PERCENT_144 144 +#define DPI_PERCENT_168 168 #define DPI_PERCENT_192 192 #define DPI_PERCENT_240 240 #define DPI_PERCENT_288 288 @@ -50,10 +51,9 @@ typedef struct _toolbar_data char gcolor[OVEC_LEN]; } toolbar_data; -int g_toolbar_size = 0; - enum {READ_FD, WRITE_FD}; -static int g_toolbar_height; +static int g_toolbar_icon = 0; +static int g_toolbar_height = 0; static int fd_stdout; static int fd_pipe[2]; static int m_index; @@ -67,7 +67,7 @@ static HIMAGELIST img_list1; static HIMAGELIST img_list2; static int -on_toolbar_fill_params(toolbar_data *pdata, const int resid) +on_toolbar_fill_params(const HWND hwnd, toolbar_data *pdata, const int resid) { int cx = GetSystemMetrics(SM_CXSCREEN); int cy = GetSystemMetrics(SM_CYSCREEN); @@ -83,7 +83,7 @@ on_toolbar_fill_params(toolbar_data *pdata, const int resid) } if (resid == IDB_SIZE_1) { - const uint32_t dpi = eu_get_dpi(NULL); + const uint32_t dpi = eu_get_dpi(hwnd); if (dpi >= DPI_PERCENT_480) { pdata->bmp_wh = 128; @@ -158,17 +158,17 @@ on_toolbar_fill_params(toolbar_data *pdata, const int resid) } if (pdata->bmp_wh > 0) { - pdata->bar_wh = pdata->bmp_wh + 10; + g_toolbar_height = pdata->bar_wh = pdata->bmp_wh + 10; } - return pdata->bar_wh; + return g_toolbar_height; } static bool -on_toolbar_init_params(toolbar_data **pdata, const int resid) +on_toolbar_init_params(const HWND hwnd, toolbar_data **pdata, const int resid) { if ((*pdata = (toolbar_data *)calloc(1, sizeof(toolbar_data))) != NULL) { - return on_toolbar_fill_params(*pdata, resid) > 0; + return on_toolbar_fill_params(hwnd, *pdata, resid) >= 0; } return false; } @@ -225,7 +225,7 @@ on_toolbar_setup_button(int id, int flags) HWND on_toolbar_hwnd(void) { - HWND hwnd = eu_module_hwnd(); + HWND hwnd = eu_hwnd_self(); return hwnd ? GetDlgItem(hwnd, IDC_TOOLBAR) : NULL; } @@ -239,19 +239,16 @@ on_toolbar_destroy(HWND hwnd) } } +int +on_toolbar_get_height(void) +{ + return (eu_get_config()->m_toolbar == IDB_SIZE_0 ? 0 : g_toolbar_height); +} + void -on_toolbar_adjust_box(void) +on_toolbar_set_height(int resid) { - int m_bar = eu_get_config()->m_toolbar; - if (m_bar == IDB_SIZE_0) - { - g_toolbar_height = 0; - } - else - { - toolbar_data data = {0}; - g_toolbar_height = on_toolbar_fill_params(&data, m_bar); - } + g_toolbar_height = resid == IDB_SIZE_0 ? 0 : resid + 10; } void @@ -659,7 +656,7 @@ on_toolbar_lua_exec(eu_tabpage *pnode) int read_len = 0; char *std_buffer = NULL; pnode->presult->pwant = on_toolbar_no_highlight; - on_proc_resize(NULL); + eu_window_resize(NULL); do_lua_setting_path(pnode); if ((std_buffer = (char *)calloc(1, MAX_OUTPUT_BUF+1))) { @@ -724,7 +721,7 @@ on_toolbar_mk_temp(wchar_t ***vec_files) if (on_tabpage_sel_number(&v, true) > 0 && v) { const int size = (int)cvector_size(v); - // 改成函数调用, cvector宏定义在一个函数里, 导致clang瞎优化 + // 改成函数调用, cvector宏定义在一个函数里, clang优化出现问题 on_toolbar_create_file(v, size, vec_files); } cvector_freep(&v); @@ -757,7 +754,7 @@ do_extra_actions(void *lp) WCHAR *plugin = NULL; if (wine && (plugin = util_winexy_get())) { - _snwprintf(cmd_exec, len, L"%s \"%s\" ", plugin, abs_path); + _snwprintf(cmd_exec, len, L"%s \\\"%s\\\" ", plugin, abs_path); free(plugin); } else @@ -769,7 +766,7 @@ do_extra_actions(void *lp) WCHAR unix_path[MAX_PATH] = {0}; if (i == count - 1) { - wcsncat(cmd_exec, L"\"", len); + wcsncat(cmd_exec, wine ? L"\\\"" : L"\"", len); if (wine && util_get_unix_file_name(vec_files[i], unix_path, MAX_PATH)) { wcsncat(cmd_exec, unix_path, len); @@ -778,11 +775,11 @@ do_extra_actions(void *lp) { wcsncat(cmd_exec, vec_files[i], len); } - wcsncat(cmd_exec, L"\"", len); + wcsncat(cmd_exec, wine ? L"\\\"" : L"\"", len); } else { - wcsncat(cmd_exec, L"\"", len); + wcsncat(cmd_exec, wine ? L"\\\"" : L"\"", len); if (wine && util_get_unix_file_name(vec_files[i], unix_path, MAX_PATH)) { wcsncat(cmd_exec, unix_path, len); @@ -791,7 +788,7 @@ do_extra_actions(void *lp) { wcsncat(cmd_exec, vec_files[i], len); } - wcsncat(cmd_exec, L"\" ", len); + wcsncat(cmd_exec, wine ? L"\\\"" : L"\" ", len); } } if ((handle = eu_new_process(cmd_exec, NULL, NULL, 2, NULL))) @@ -823,7 +820,7 @@ void on_toolbar_execute_script(void) { eu_tabpage *p = on_tabpage_focus_at(); - if (p && !p->hex_mode && p->doc_ptr) + if (p && !TAB_HEX_MODE(p) && p->doc_ptr) { intptr_t param = (intptr_t)p->doc_ptr->doc_type; if (strlen(eu_get_config()->m_actions[param]) > 1) @@ -877,6 +874,34 @@ on_toolbar_menu_callback(HMENU hpop, void *param) } } +static bool +on_toolbar_generate_img(const HWND hwnd, toolbar_data **pdata, const int resid) +{ + on_toolbar_init_params(hwnd, pdata, resid); + if (!*pdata) + { + return false; + } + if (img_list1) + { + ImageList_Destroy(img_list1); + } + if (img_list2) + { + ImageList_Destroy(img_list2); + img_list2 = NULL; + } + if ((img_list1 = create_img_list(*pdata, true)) == NULL) + { + return false; + } + if ((img_list2 = create_img_list(*pdata, false)) == NULL) + { + return false; + } + return true; +} + /***************************************************************** * 工具栏回调函数, 接受工具栏点击消息, 以及销毁自身资源 *****************************************************************/ @@ -899,6 +924,20 @@ toolbar_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) on_toolbar_setpos_clipdlg(g_clip_hwnd, eu_module_hwnd()); break; } + case WM_THEMECHANGED: + { + if (eu_hwnd_self() == (HWND)wParam) + { // 忽略自动发送的WM_THEMECHANGED消息 + toolbar_data *data = NULL; + if (on_toolbar_generate_img((HWND)wParam, &data, eu_get_config()->m_toolbar)) + { + SendMessage(hwnd, TB_SETIMAGELIST, (WPARAM) 0, (LPARAM) img_list1); + SendMessage(hwnd, TB_SETDISABLEDIMAGELIST, (WPARAM) 0, (LPARAM) img_list2); + } + eu_safe_free(data); + } + break; + } case WM_DESTROY: { if (img_list1) @@ -976,9 +1015,15 @@ on_toolbar_cmd_start(eu_tabpage *pnode) } int -on_toolbar_height(void) +on_toolbar_icon_get(void) { - return g_toolbar_height; + return (g_toolbar_icon); +} + +void +on_toolbar_icon_set(const int size) +{ + g_toolbar_icon = (int)size; } void @@ -993,7 +1038,7 @@ on_toolbar_update_button(void) on_toolbar_setup_button(IDM_FILE_SAVEAS, 2); on_toolbar_setup_button(IDM_FILE_CLOSE, 2); on_toolbar_setup_button(IDM_FILE_PRINT, 2); - on_toolbar_setup_button(IDM_EDIT_CUT, !pnode->pmod && (pnode->hex_mode || util_can_selections(pnode)) ? 2 : 1); + on_toolbar_setup_button(IDM_EDIT_CUT, !pnode->pmod && (TAB_HEX_MODE(pnode) || util_can_selections(pnode)) ? 2 : 1); on_toolbar_setup_button(IDM_EDIT_COPY, !pnode->pmod && TAB_NOT_NUL(pnode) ? 2 : 1); on_toolbar_setup_button(IDM_EDIT_PASTE, !pnode->pmod ? 2 : 1); on_toolbar_setup_button(IDM_SEARCH_FIND, !pnode->pmod ? 2 : 1); @@ -1001,16 +1046,44 @@ on_toolbar_update_button(void) on_toolbar_setup_button(IDM_SEARCH_FINDNEXT, !pnode->pmod ? 2 : 1); on_toolbar_setup_button(IDM_EDIT_UNDO, !pnode->pmod && eu_sci_call(pnode, SCI_CANUNDO, 0, 0) ? 2 : 1); on_toolbar_setup_button(IDM_EDIT_REDO, !pnode->pmod && eu_sci_call(pnode, SCI_CANREDO, 0, 0) ? 2 : 1); - on_toolbar_setup_button(IDM_SEARCH_TOGGLE_BOOKMARK, !pnode->pmod && !pnode->hex_mode ? 2 : 1); - on_toolbar_setup_button(IDM_SEARCH_GOTO_PREV_BOOKMARK, !pnode->pmod && !pnode->hex_mode ? 2 : 1); - on_toolbar_setup_button(IDM_SEARCH_GOTO_NEXT_BOOKMARK, !pnode->pmod && !pnode->hex_mode ? 2 : 1); - on_toolbar_setup_button(IDM_VIEW_HEXEDIT_MODE, (pnode->codepage != IDM_OTHER_BIN) && TAB_NOT_NUL(pnode) ? 2 : 1); + on_toolbar_setup_button(IDM_SEARCH_TOGGLE_BOOKMARK, !pnode->pmod && !TAB_HEX_MODE(pnode) ? 2 : 1); + on_toolbar_setup_button(IDM_SEARCH_GOTO_PREV_BOOKMARK, !pnode->pmod && !TAB_HEX_MODE(pnode) ? 2 : 1); + on_toolbar_setup_button(IDM_SEARCH_GOTO_NEXT_BOOKMARK, !pnode->pmod && !TAB_HEX_MODE(pnode) ? 2 : 1); + on_toolbar_setup_button(IDM_VIEW_HEXEDIT_MODE, TAB_NOT_BIN(pnode) && (TAB_HAS_PDF(pnode) || TAB_NOT_NUL(pnode)) ? 2 : 1); on_toolbar_setup_button(IDM_VIEW_SYMTREE, (pnode->hwnd_symlist || pnode->hwnd_symtree) ? 2 : 1); on_toolbar_setup_button(IDM_VIEW_FULLSCREEN, 2); on_toolbar_setup_button(IDM_FILE_REMOTE_FILESERVERS, util_exist_libcurl() ? 2 : 1); on_toolbar_setup_button(IDM_VIEW_ZOOMIN, 2); on_toolbar_setup_button(IDM_VIEW_ZOOMOUT, 2); - on_toolbar_setup_button(IDM_SCRIPT_EXEC, (!pnode->hex_mode && pnode->doc_ptr) ? 2 : 1); + on_toolbar_setup_button(IDM_SCRIPT_EXEC, (!TAB_HEX_MODE(pnode) && pnode->doc_ptr) ? 2 : 1); + // dark theme下需要重新绘制 + on_toolbar_redraw(eu_hwnd_self()); + } + } +} + +void +on_toolbar_redraw(HWND hwnd) +{ + UpdateWindowEx(on_toolbar_hwnd()); +} + +void +on_toolbar_size(void) +{ + HWND hwnd = on_toolbar_hwnd(); + if (hwnd) + { + if (eu_get_config()->m_toolbar != IDB_SIZE_0) + { + RECT rc; + GetClientRect(eu_hwnd_self(), &rc); + int width = rc.right - rc.left; + eu_setpos_window(hwnd, HWND_TOP, 0, 0, width, on_toolbar_get_height(), SWP_SHOWWINDOW); + } + else + { + eu_setpos_window(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); } } } @@ -1024,11 +1097,11 @@ on_toolbar_refresh(HWND hwnd) DestroyWindow(h_tool); } refresh_clipboard(); // dpi改变时重新渲染图标 - return (on_toolbar_create(hwnd) == 0); + return (on_toolbar_create_dlg(hwnd) == 0); } int -on_toolbar_create(HWND parent) +on_toolbar_create_dlg(HWND parent) { int ret = 0; HWND htool = NULL; @@ -1041,7 +1114,7 @@ on_toolbar_create(HWND parent) do { int i = 0, j = 0; - const int style = WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|TBSTYLE_TOOLTIPS|TBSTYLE_FLAT|TBSTYLE_CUSTOMERASE|CCS_TOP|CCS_NODIVIDER; + int style = WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|TBSTYLE_TOOLTIPS|TBSTYLE_FLAT|CCS_TOP|CCS_NODIVIDER; /********************************************************************* * iBitmap(0), 第i个位图 * idCommand(0), WM_COMMAND消息响应的ID @@ -1069,18 +1142,7 @@ on_toolbar_create(HWND parent) ret = 1; break; } - on_toolbar_init_params(&pdata, eu_get_config()->m_toolbar); - if (!pdata) - { - ret = 1; - break; - } - if ((img_list1 = create_img_list(pdata, true)) == NULL) - { - ret = 1; - break; - } - if ((img_list2 = create_img_list(pdata, false)) == NULL) + if (!on_toolbar_generate_img(parent, &pdata, eu_get_config()->m_toolbar)) { ret = 1; break; @@ -1108,7 +1170,11 @@ on_toolbar_create(HWND parent) ptb[i].fsStyle = TBSTYLE_SEP; } } - htool = CreateWindowEx(WS_EX_PALETTEWINDOW, //TBSTYLE_EX_DOUBLEBUFFER + if (on_dark_enable()) + { + style |= TBSTYLE_CUSTOMERASE; + } + htool = CreateWindowEx(WS_EX_PALETTEWINDOW, TOOLBARCLASSNAME, _T(""), style, @@ -1137,7 +1203,6 @@ on_toolbar_create(HWND parent) SendMessage(htool, TB_SETIMAGELIST, (WPARAM) 0, (LPARAM) img_list1); SendMessage(htool, TB_SETDISABLEDIMAGELIST, (WPARAM) 0, (LPARAM) img_list2); SendMessage(htool, TB_SETMAXTEXTROWS, 0, 0); - SendMessage(htool, TB_AUTOSIZE, 0, 0); on_dark_tips_theme(htool, TB_GETTOOLTIPS); } while(0); free(str); diff --git a/src/eu_toolbar.h b/src/eu_toolbar.h index 012db376..379e3788 100644 --- a/src/eu_toolbar.h +++ b/src/eu_toolbar.h @@ -27,17 +27,20 @@ extern "C" { #endif -extern int g_toolbar_size; +void on_toolbar_icon_set(const int size); void on_toolbar_setpos_clipdlg(HWND hwnd, HWND parent); -void on_toolbar_adjust_box(void); void on_toolbar_destroy(HWND hwnd); void on_toolbar_update_button(void); void on_toolbar_execute_script(void); void on_toolbar_lua_exec(eu_tabpage *pnode); void on_toolbar_setup_button(int id, int flags); void on_toolbar_no_highlight(void *lp); -int on_toolbar_height(void); -int on_toolbar_create(HWND hwnd); +void on_toolbar_redraw(HWND hwnd); +void on_toolbar_size(); +void on_toolbar_set_height(int resid); +int on_toolbar_icon_get(void); +int on_toolbar_get_height(void); +int on_toolbar_create_dlg(HWND hwnd); bool on_toolbar_refresh(HWND hwnd); HWND on_toolbar_create_clipbox(HWND hwnd); HWND on_toolbar_clip_hwnd(void); diff --git a/src/eu_treebar.c b/src/eu_treebar.c index 16e888f5..a52064e0 100644 --- a/src/eu_treebar.c +++ b/src/eu_treebar.c @@ -1172,7 +1172,7 @@ on_filetree_node_dbclick(void) } if (!err && TabCtrl_GetItemCount(g_tabpages) < 1) { // 建立一个空白标签页 - err = on_file_new(); + err = on_file_new(NULL); } return err; } @@ -1609,11 +1609,13 @@ filetree_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } } TreeView_SetItem(hwnd, &item); + break; } - break; case NM_DBLCLK: + { on_filetree_node_dbclick(); break; + } case TVN_BEGINLABELEDIT: { LPNMTVDISPINFO pinfo = (LPNMTVDISPINFO) lpnmhdr; @@ -1623,8 +1625,8 @@ filetree_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; } SetWindowLongPtr(hwnd, GWLP_USERDATA, (uintptr_t) old_tvd); + break; } - break; case TVN_ENDLABELEDIT: { LPNMTVDISPINFO pinfo = (LPNMTVDISPINFO) lpnmhdr; @@ -1635,7 +1637,9 @@ filetree_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; } default: + { break; + } } break; } @@ -1785,11 +1789,17 @@ on_treebar_load_imglist(HWND hwnd) void on_treebar_update_theme(void) { - SendMessage(g_filetree, WM_SETFONT, (WPARAM) on_theme_font_hwnd(), 0); - SendMessage(g_filetree, TVM_SETTEXTCOLOR, 0, eu_get_theme()->item.text.color); + if (util_under_wine() && eu_get_theme()->item.text.color == 0x00D4D4D4) + { + SendMessage(g_filetree, TVM_SETTEXTCOLOR, 0, 0xFFFFFF); + } + else + { + SendMessage(g_filetree, TVM_SETTEXTCOLOR, 0, eu_get_theme()->item.text.color); + } SendMessage(g_filetree, TVM_SETBKCOLOR, 0, eu_get_theme()->item.text.bgcolor); // 向控件发送消息, 要不然滚动条可能不会重绘 - on_dark_set_theme(g_filetree, on_dark_enable() ? L"DarkMode_Explorer" : L"", NULL); + on_dark_set_theme(g_filetree, on_dark_enable() ? DARKMODE : L"", NULL); } LRESULT CALLBACK @@ -1798,57 +1808,42 @@ treebar_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_ERASEBKGND: - if (!on_dark_enable()) - { - break; - } + { RECT rc = {0}; GetClientRect(hwnd, &rc); - FillRect((HDC)wParam, &rc, (HBRUSH)on_dark_get_bgbrush()); + FillRect((HDC)wParam, &rc, eu_theme_index() == THEME_WHITE ? GetSysColorBrush(COLOR_MENU) : (HBRUSH)on_dark_get_bgbrush()); return 1; + } case WM_PAINT: { - if (GetWindowLongPtr(hwnd, GWL_STYLE) & TCS_OWNERDRAWFIXED) - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, & ps); - HBRUSH hbr_bkgnd = (HBRUSH)on_dark_get_bgbrush(); - // 绘制管理器标签 - HGDIOBJ old_font = SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); - if (old_font) + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, & ps); + const bool dark = on_dark_enable(); + // 绘制管理器标签 + HGDIOBJ old_font = SelectObject(hdc, on_theme_font_hwnd()); + if (old_font) + { + RECT rc; + TabCtrl_GetItemRect(hwnd, 0, &rc); + set_tabface_color(hdc, dark); + set_text_color(hdc, dark); + FrameRect(hdc, &rc, dark ? GetSysColorBrush(COLOR_3DDKSHADOW) : GetSysColorBrush(COLOR_BTNSHADOW)); + LOAD_I18N_RESSTR(IDC_MSG_EXPLORER, m_text); + if (STR_NOT_NUL(m_text)) { - RECT rc; - TabCtrl_GetItemRect(hwnd, 0, &rc); - set_btnface_color(hdc, true); - set_text_color(hdc, true); - FrameRect(hdc, &rc, GetSysColorBrush(COLOR_3DDKSHADOW)); - LOAD_I18N_RESSTR(IDC_MSG_EXPLORER, m_text); - if (STR_NOT_NUL(m_text)) - { - DrawText(hdc, m_text, (int)_tcslen(m_text), &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - } - SelectObject(hdc, old_font); + DrawText(hdc, m_text, (int)_tcslen(m_text), &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } - EndPaint(hwnd, &ps); + SelectObject(hdc, old_font); } + EndPaint(hwnd, &ps); break; } case WM_DPICHANGED: { - on_treebar_update_theme(); break; } case WM_THEMECHANGED: { - uintptr_t style = GetWindowLongPtr(hwnd, GWL_STYLE); - if (on_dark_enable()) - { - style & TCS_OWNERDRAWFIXED ? (void)0 : SetWindowLongPtr(hwnd, GWL_STYLE, style | TCS_OWNERDRAWFIXED); - } - else if (style & TCS_OWNERDRAWFIXED) - { - SetWindowLongPtr(hwnd, GWL_STYLE, style & ~TCS_OWNERDRAWFIXED); - } break; } case WM_DESTROY: @@ -1873,7 +1868,7 @@ on_treebar_create_box(HWND hwnd) { DestroyWindow(g_treebar); } - g_treebar = CreateWindow(WC_TABCONTROL, NULL, WS_CHILD|TCS_FOCUSNEVER, 0, 0, 0, 0, hwnd, (HMENU) IDM_TREE_BAR, eu_module_handle(), NULL); + g_treebar = CreateWindow(WC_TABCONTROL, NULL, WS_CHILD|TCS_FIXEDWIDTH|TCS_FOCUSNEVER, 0, 0, 0, 0, hwnd, (HMENU) IDM_TREE_BAR, eu_module_handle(), NULL); if (g_treebar == NULL) { return EUE_POINT_NULL; @@ -1893,7 +1888,7 @@ on_treebar_create_box(HWND hwnd) DestroyWindow(g_treebar); return EUE_POINT_NULL; } - SendMessage(g_treebar, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0); + on_theme_update_font(filebar_id); return SKYLARK_OK; } @@ -1959,6 +1954,7 @@ on_treebar_create_dlg(HWND hwnd) err = EUE_POINT_NULL; break; } + on_theme_update_font(filetree_id); on_treebar_update_theme(); }while(0); if (err) @@ -1978,33 +1974,87 @@ on_treebar_create_dlg(HWND hwnd) } void -on_treebar_adjust_box(RECT *ptf) +on_treebar_size(void) { - RECT rect_main; - GetClientRect(eu_module_hwnd(), &rect_main); + HDWP hdwp = BeginDeferWindowPos(3); + if (g_treebar && hdwp) + { + RECT rect_treebar = {0}; + on_treebar_adjust_box(&rect_treebar, NULL); + if (eu_get_config()->m_ftree_show) + { + RECT rect_filetree = {0}; + on_treebar_adjust_filetree(&rect_treebar, &rect_filetree); + DeferWindowPos(hdwp, + g_treebar, + HWND_TOP, + rect_treebar.left, + rect_treebar.top, + rect_treebar.right - rect_treebar.left, + rect_treebar.bottom - rect_treebar.top, + SWP_SHOWWINDOW); + DeferWindowPos(hdwp, + g_filetree, + HWND_TOP, + rect_filetree.left, + rect_filetree.top, + rect_filetree.right - rect_filetree.left, + rect_filetree.bottom - rect_filetree.top, + SWP_SHOWWINDOW); + DeferWindowPos(hdwp, + g_splitter_treebar, + HWND_TOP, + rect_treebar.right, + rect_filetree.top, + SPLIT_WIDTH, + rect_filetree.bottom - rect_filetree.top, + SWP_SHOWWINDOW); + } + else + { + DeferWindowPos(hdwp, g_treebar, 0, 0, 0, 0, 0, SWP_HIDEWINDOW); + DeferWindowPos(hdwp, g_filetree, 0, 0, 0, 0, 0, SWP_HIDEWINDOW); + DeferWindowPos(hdwp, g_splitter_treebar, 0, 0, 0, 0, 0, SWP_HIDEWINDOW); + } + } + EndDeferWindowPos(hdwp); +} + +void +on_treebar_adjust_box(RECT *ptf, RECT *prc) +{ + RECT rect_main = {0}; + GetClientRect(eu_module_hwnd(), prc ? prc : &rect_main); + if (prc == NULL) + { + prc = &rect_main; + } if (!eu_get_config()->m_ftree_show) { ptf->left = 0; ptf->right = 0; - ptf->top = rect_main.top + on_toolbar_height(); - ptf->bottom = rect_main.bottom; + ptf->top = prc->top + on_toolbar_get_height(); + ptf->bottom = prc->bottom - on_statusbar_height(); } else { - ptf->left = rect_main.left; - ptf->right = rect_main.left + eu_get_config()->file_tree_width; - ptf->top = rect_main.top + on_toolbar_height(); - ptf->bottom = rect_main.bottom - on_statusbar_height(); + ptf->left = prc->left; + ptf->right = prc->left + eu_get_config()->file_tree_width; + ptf->top = prc->top + on_toolbar_get_height(); + ptf->bottom = prc->bottom - on_statusbar_height(); } } void -on_treebar_adjust_filetree(RECT *rect_filebar, RECT *rect_filetree) +on_treebar_adjust_filetree(const RECT *rect_filebar, RECT *rect_filetree) { - rect_filetree->left = FILETREE_MARGIN_LEFT; - rect_filetree->right = rect_filebar->right - FILETREE_MARGIN_RIGHT; - rect_filetree->top = rect_filebar->top + TABS_HEIGHT_DEFAULT + FILETREE_MARGIN_TOP; - rect_filetree->bottom = rect_filebar->bottom - FILETREE_MARGIN_BOTTOM; + if (g_treebar) + { + rect_filetree->left = FILETREE_MARGIN_LEFT; + rect_filetree->right = rect_filebar->right - FILETREE_MARGIN_RIGHT; + rect_filetree->top = rect_filebar->top + util_tab_height(g_treebar, 0) + FILETREE_MARGIN_TOP; + rect_filetree->bottom = rect_filebar->bottom - FILETREE_MARGIN_BOTTOM; + } } tree_data * @@ -2211,6 +2261,7 @@ on_treebar_locate_path(const TCHAR *pathname) TreeView_SelectItem(g_filetree, hti); TreeView_EnsureVisible(g_filetree, hti); SendMessage(g_filetree, WM_SETFOCUS, 0, 0); + on_treebar_size(); eu_window_resize(eu_module_hwnd()); } util_free(m_dup); diff --git a/src/eu_treebar.h b/src/eu_treebar.h index 74dbb453..6ad87726 100644 --- a/src/eu_treebar.h +++ b/src/eu_treebar.h @@ -60,21 +60,22 @@ typedef enum _IMG_MOUNT extern HWND g_treebar; extern HWND g_filetree; -tree_data *on_treebar_get_treeview(HTREEITEM hti); -tree_data *on_treebar_add_favorite(HTREEITEM parent, const int index, void *pdata); -void on_treebar_update_theme(void); -void on_treebar_adjust_box(RECT *ptf); -void on_treebar_adjust_filetree(RECT *treebar, RECT *rect); int on_treebar_load_remote(HWND hwnd, remotefs *pserver); int on_treebar_locate_path(const TCHAR *pathname); int on_treebar_create_box(HWND hwnd); int on_treebar_create_dlg(HWND hwnd); int on_treebar_refresh_node(HTREEITEM hti_parent); bool on_treebar_variable_initialized(HWND *pd); +void on_treebar_size(void); void on_treebar_wait_hwnd(void); void on_treebar_update_addr(remotefs *pserver); void on_treebar_data_destoy(tree_data **ptvd); +void on_treebar_update_theme(void); +void on_treebar_adjust_box(RECT *ptf, RECT *prc); +void on_treebar_adjust_filetree(const RECT *rect_filebar, RECT *rect_filetree); HTREEITEM on_treebar_get_path(tree_data **ptvd); +tree_data *on_treebar_get_treeview(HTREEITEM hti); +tree_data *on_treebar_add_favorite(HTREEITEM parent, const int index, void *pdata); #ifdef __cplusplus } diff --git a/src/eu_updatechecker.c b/src/eu_updatechecker.c index c3abbd12..3d72dacd 100644 --- a/src/eu_updatechecker.c +++ b/src/eu_updatechecker.c @@ -423,3 +423,13 @@ on_update_check(const int ident) SendMessage(hwnd, WM_UPCHECK_STATUS, -1, 0); } } + +bool +on_update_lookup(void) +{ + if (_tcsnicmp(eu_config_path, eu_module_path, _tcslen(eu_module_path)) && !util_try_path(eu_module_path)) + { + return (eu_get_config()->upgrade.enable = false); + } + return true; +} diff --git a/src/eu_updatechecker.h b/src/eu_updatechecker.h index 485857ee..b9a2d023 100644 --- a/src/eu_updatechecker.h +++ b/src/eu_updatechecker.h @@ -32,6 +32,7 @@ void on_update_check(const int ident); void on_update_sql(void); void on_update_thread_wait(void); bool on_update_do(void); +bool on_update_lookup(void); #ifdef __cplusplus } diff --git a/src/eu_util.c b/src/eu_util.c index 50a0027e..2ff06cd2 100644 --- a/src/eu_util.c +++ b/src/eu_util.c @@ -378,7 +378,7 @@ util_string_to_struct(const char *buffer, void *buf, size_t len) void util_wait_cursor(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode) + if (pnode && !TAB_HEX_MODE(pnode)) { eu_sci_call(pnode, SCI_SETCURSOR, (WPARAM) SC_CURSORWAIT, 0); } @@ -388,7 +388,7 @@ void util_restore_cursor(eu_tabpage *pnode) { POINT pt; - if (pnode && !pnode->hex_mode) + if (pnode && !TAB_HEX_MODE(pnode)) { eu_sci_call(pnode, SCI_SETCURSOR, (WPARAM) SC_CURSORNORMAL, 0); GetCursorPos(&pt); @@ -1321,6 +1321,34 @@ util_strdup_content(eu_tabpage *pnode, size_t *plen) return ptext; } +char * +util_memdup(char **p, const char *text) +{ + if (p && text) + { + size_t text_len = strlen(text) + (*p ? strlen(*p) : 0); + if (*p) + { + char *dst = (char *)realloc(*p, text_len + 1); + if (dst) + { + strncat(dst, text, text_len); + if (*p != dst) + { + *p = dst; + } + } + } + else if ((*p = (char *)malloc(text_len + 1))) + { + (*p)[text_len] = 0; + _snprintf(*p, text_len, "%s", text); + } + return (*p); + } + return NULL; +} + /************************************************** * 验证字符的有效性 *************************************************/ @@ -1875,10 +1903,34 @@ util_mk_temp(TCHAR *file_path, TCHAR *ext) WCHAR * util_winexy_get(void) { - WCHAR *plugin = (WCHAR *)calloc(sizeof(WCHAR), (MAX_PATH+1)); + WCHAR *plugin = (WCHAR *)calloc(sizeof(WCHAR), (MAX_BUFFER+1)); + if (plugin && STR_NOT_NUL(eu_module_path)) + { + _snwprintf(plugin, MAX_BUFFER, L"/bin/wine \"%s\\plugins\\np_winexy.dll\"", eu_module_path); + util_path2unix(plugin, eu_int_cast(_tcslen(plugin))); + } + return plugin; +} + +WCHAR * +util_winexy_hide(void) +{ + WCHAR *plugin = (WCHAR *)calloc(sizeof(WCHAR), (MAX_BUFFER+1)); + if (plugin && STR_NOT_NUL(eu_module_path)) + { + _snwprintf(plugin, MAX_BUFFER, L"/bin/wine \"%s\\plugins\\np_winexy.dll\" hide.exe", eu_module_path); + util_path2unix(plugin, eu_int_cast(_tcslen(plugin))); + } + return plugin; +} + +WCHAR * +util_winexy_tool(void) +{ + WCHAR *plugin = (WCHAR *)calloc(sizeof(WCHAR), (MAX_BUFFER+1)); if (plugin && STR_NOT_NUL(eu_module_path)) { - _snwprintf(plugin, MAX_PATH, L"/bin/wine \"%s\\plugins\\np_winexy.dll\"", eu_module_path); + _snwprintf(plugin, MAX_BUFFER, L"/bin/wine \"%s\\plugins\\np_winexy.dll\" xtool \"%s\\plugins\\xtool\"", eu_module_path, eu_module_path); util_path2unix(plugin, eu_int_cast(_tcslen(plugin))); } return plugin; @@ -1898,9 +1950,14 @@ util_to_abs(const char *path) { return NULL; } - util_unix2path(lpfile, (const int)_tcslen(lpfile)); - // 如果路径有引号, 去除 - util_wstr_unquote(lpfile, sizeof(lpfile)); + if (!wine) + { + util_unix2path(lpfile, (const int)_tcslen(lpfile)); + } + if (true) + { // 如果路径有引号, 去除 + util_wstr_unquote(lpfile, sizeof(lpfile)); + } if (lpfile[0] == L'%') { int n = 1; @@ -1951,7 +2008,7 @@ util_to_abs(const char *path) { pret = _wcsdup(lpfile); } - if (wine && pret && util_get_unix_file_name(pret, lpfile, MAX_BUFFER)) + if (wine && STR_NOT_NUL(pret) && pret[0] != L'/' && util_get_unix_file_name(pret, lpfile, MAX_BUFFER)) { _snwprintf(pret, MAX_BUFFER, L"%s", lpfile); } @@ -2197,6 +2254,7 @@ util_product_name(LPCWSTR filepath, LPWSTR out_string, size_t len) LANGANDCODEPAGE *lptranslate = NULL; do { + out_string[0] = L'\0'; if ((h_ver = util_init_verinfo()) == NULL) { break; @@ -2222,19 +2280,14 @@ util_product_name(LPCWSTR filepath, LPWSTR out_string, size_t len) } for (uint16_t i = 0; i < (cb_translate / sizeof(LANGANDCODEPAGE)); i++) { - sntprintf(dw_block, - FILESIZE, - L"\\StringFileInfo\\%04x%04x\\ProductName", - lptranslate[i].wLanguage, - lptranslate[i].wCodePage); - - ret = pfnVerQueryValueW((LPCVOID) pbuffer, (LPCWSTR) dw_block, (LPVOID *) &ptmp, &cb_translate); - if (ret) + sntprintf(dw_block, FILESIZE, L"\\StringFileInfo\\%04x%04x\\ProductName", lptranslate[i].wLanguage, lptranslate[i].wCodePage); + if ((ret = pfnVerQueryValueW((LPCVOID) pbuffer, (LPCWSTR) dw_block, (LPVOID *) &ptmp, &cb_translate))) { - out_string[0] = L'\0'; - wcsncpy(out_string, (LPCWSTR) ptmp, len); - ret = wcslen(out_string) > 1; - if (ret) break; + wcsncpy(out_string, (LPCWSTR) ptmp, len - 1); + if ((ret = wcslen(out_string) > 1)) + { + break; + } } } } while (0); @@ -2448,33 +2501,32 @@ util_get_hwnd(const uint32_t pid) TCHAR * util_which(const TCHAR *name) { + int len = 0; bool diff = false; bool add_suf = true; TCHAR *file = NULL; TCHAR *env_path = NULL; - TCHAR sz_work[MAX_PATH + 1] = {0}; + TCHAR sz_work[MAX_BUFFER] = {0}; const TCHAR *delimiter = _T(";"); - TCHAR *path = _tgetenv(_T("PATH")); + const TCHAR *path = (const TCHAR *)_tgetenv(_T("PATH")); TCHAR *av[] = {_T(".exe"), _T(".com"), _T(".cmd"), _T(".bat"), NULL}; TCHAR *dot = _tcsrchr(name, _T('.')); - int len = eu_int_cast(_tcslen(path)) + (3 * MAX_PATH); - if (!path) + if (!path || !GetSystemDirectory(sz_work, MAX_BUFFER - 1)) { return NULL; } - GetSystemDirectory(sz_work, MAX_PATH); if (!sz_work[0] || !eu_module_path[0]) { return NULL; } - if ((env_path = (TCHAR *)calloc(sizeof(TCHAR), len + 1)) == NULL) + if (true) { - return NULL; + len = eu_int_cast(_tcslen(path)) + (3 * MAX_BUFFER); + diff = _tcscmp(sz_work, eu_module_path) != 0; } - diff = _tcscmp(sz_work, eu_module_path) != 0; - if (util_under_wine()) + if ((env_path = (TCHAR *)calloc(sizeof(TCHAR), len + 1)) == NULL) { - add_suf = false; + return NULL; } else if (dot) { @@ -2487,7 +2539,7 @@ util_which(const TCHAR *name) } } } - if ((file = (TCHAR *)calloc(sizeof(TCHAR), MAX_PATH)) != NULL) + if ((file = (TCHAR *)calloc(sizeof(TCHAR), MAX_BUFFER)) != NULL) { if (diff) { @@ -2512,7 +2564,7 @@ util_which(const TCHAR *name) { quote = false; } - _sntprintf(file, MAX_PATH, _T("%s\\%s"), quote? &tok[1] : tok, name); + _sntprintf(file, MAX_BUFFER - 1, _T("%s\\%s"), quote? &tok[1] : tok, name); do { struct _stat st; @@ -2523,7 +2575,7 @@ util_which(const TCHAR *name) } if (add_suf && av[i]) { - _sntprintf(file, MAX_PATH, _T("%s\\%s%s"), quote? &tok[1] : tok, name, av[i]); + _sntprintf(file, MAX_BUFFER - 1, _T("%s\\%s%s"), quote? &tok[1] : tok, name, av[i]); } } while (av[i++]); tok = _tcstok(NULL, delimiter); @@ -2835,7 +2887,7 @@ util_explorer_open(eu_tabpage *pnode) wchar_t unix_path[MAX_PATH] = {0}; if (util_get_unix_file_name(pnode->pathfile, unix_path, MAX_PATH - 1) && (plugin = util_winexy_get())) { - _sntprintf(cmd_exec, MAX_BUFFER - 1, L"%s %s \"%s\"", plugin, L"explorer.exe", unix_path); + _sntprintf(cmd_exec, MAX_BUFFER - 1, L"%s %s \\\"%s\\\"", plugin, L"explorer.exe", unix_path); free(plugin); CloseHandle(eu_new_process(cmd_exec, NULL, pnode->pathname, 2, NULL)); } @@ -3145,6 +3197,16 @@ util_shield_icon(HINSTANCE hinst, LPCTSTR name) return hmap; } +void +util_updateui_titlebar(const HWND hwnd) +{ + LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE); + SetWindowLongPtr(hwnd, GWL_STYLE, (style &= ~WS_CAPTION)); + eu_setpos_window(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED); + SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_CAPTION); + eu_setpos_window(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED); +} + void util_updateui_icon(const HWND hwnd, const bool fnshow) { @@ -3157,7 +3219,7 @@ util_updateui_icon(const HWND hwnd, const bool fnshow) } else { - uint32_t ex = (uint32_t)GetWindowLongPtr(hwnd, GWL_EXSTYLE); + const LONG_PTR ex = GetWindowLongPtr(hwnd, GWL_EXSTYLE); SetWindowLongPtr(hwnd, GWL_EXSTYLE, ex | WS_EX_DLGMODALFRAME); SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); if ((HICON)SendMessage(hwnd, WM_GETICON, ICON_SMALL, 0)) @@ -3339,3 +3401,58 @@ util_font_available(const char *name) eu_safe_free(pname); return found; } + +bool +util_font_xy(const HWND hwnd, const HFONT hfont, int *px, int *py) +{ + HDC hdc = GetDC(hwnd); + if (hdc) + { + HGDIOBJ hold_font = NULL; + TEXTMETRIC text_metric = {0}; + if (hfont) + { + hold_font = SelectObject(hdc, (HGDIOBJ)hfont); + } + GetTextMetrics(hdc, &text_metric); + if (hold_font) + { + SelectObject(hdc, hold_font); + } + ReleaseDC(hwnd, hdc); + *px = text_metric.tmAveCharWidth; + *py = text_metric.tmHeight; + return true; + } + return false; +} + +bool +util_dark_theme(void) +{ + int buffer[32] = {0}; + uint32_t cbdata = 32; + LSTATUS res = RegGetValueW(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", + L"AppsUseLightTheme", + RRF_RT_REG_DWORD, + NULL, + buffer, + &cbdata); + return (res == ERROR_SUCCESS) && (((buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0])) == 0); +} + +int +util_tab_height(const HWND hwnd, const int width) +{ + int x, y = 0; + if (hwnd) + { + sptr_t xy = 0; + const int dpi = eu_get_dpi(hwnd); + x = eu_dpi_scale_xy(dpi, width <= 0 ? TABS_WIDTH_DEFAULT : width); + y = eu_dpi_scale_xy(dpi, TABS_HEIGHT_DEFAULT); + xy = TabCtrl_SetItemSize(hwnd, x, y); + } + return (y > TABS_HEIGHT_DEFAULT ? y : TABS_HEIGHT_DEFAULT); +} diff --git a/src/eu_util.h b/src/eu_util.h index 66df4f4c..0c432349 100644 --- a/src/eu_util.h +++ b/src/eu_util.h @@ -93,6 +93,7 @@ int util_get_hex_byte(const char *p); int util_strnspace(const char *s1, const char *s2, int *plen); int util_count_characters(const char *pstr, const int ch); +char* util_memdup(char **p, const char *text); char* util_unix_newline(const char *in, const size_t in_size); char* util_strdup_select(eu_tabpage *pnode, size_t *text_len, size_t multiple); char* util_strdup_line(eu_tabpage *pnode, const sptr_t line_number, size_t *plen); @@ -128,6 +129,7 @@ bool util_shell_path(const GUID *folder, TCHAR *path, const int len); bool util_copy_file(LPCWSTR source, LPCWSTR dest, const bool fail_exist); bool util_isxdigit_string(LPCTSTR str, const int len); bool util_has_space(uint8_t ch); +bool util_dark_theme(void); time_t util_last_time(const TCHAR *path); uint64_t util_gen_tstamp(void); void util_switch_menu_group(HMENU hmenu, int pop_id, uint32_t first_id, uint32_t last_id, uint32_t select); @@ -141,6 +143,8 @@ HANDLE util_mk_temp(TCHAR *file_path, TCHAR *ext); HWND util_create_tips(HWND hwnd_stc, HWND hwnd, TCHAR* ptext); HWND util_get_hwnd(const uint32_t pid); WCHAR* util_winexy_get(void); +WCHAR* util_winexy_hide(void); +WCHAR* util_winexy_tool(void); TCHAR* util_unix2path(TCHAR *path, const int len); TCHAR* util_path2unix(TCHAR *path, const int len); TCHAR* util_add_double_quotes(const TCHAR *path); @@ -158,21 +162,24 @@ int util_count_number(size_t number); int util_split_attr(const char *pstr, char (*pout)[MAX_PATH], int ch); int util_strim_end(char *pstr, int len); int util_num_cores(void); -void util_strcat(uint8_t **dst, const char* pstr); -void util_split(const char *pstr, const char *sep, char ***ppvec, const bool out_vec); -void util_transparent(HWND hwnd, int percent); -void util_untransparent(HWND hwnd); -void util_postion_xy(eu_tabpage *pnode, sptr_t pos, sptr_t *px, sptr_t *py); -void util_explorer_open(eu_tabpage *pnode); -void util_redraw(const HWND hwnd, const bool force); -void util_symlink_destroy(eu_tabpage *pnode); -void util_updateui_msg(const eu_tabpage *pnode); -void util_updateui_icon(const HWND hwnd, const bool fnshow); -void util_update_env(eu_tabpage *pnode); -bool util_product_name(LPCWSTR filepath, LPWSTR out_string, size_t len); -bool util_file_access(LPCTSTR filename, uint32_t *pgranted); -bool util_get_unix_file_name(LPCWSTR path, wchar_t *out, const int len); -bool util_font_available(const char *name); +int util_tab_height(const HWND hwnd, const int width); +void util_strcat(uint8_t **dst, const char* pstr); +void util_split(const char *pstr, const char *sep, char ***ppvec, const bool out_vec); +void util_transparent(HWND hwnd, int percent); +void util_untransparent(HWND hwnd); +void util_postion_xy(eu_tabpage *pnode, sptr_t pos, sptr_t *px, sptr_t *py); +void util_explorer_open(eu_tabpage *pnode); +void util_redraw(const HWND hwnd, const bool force); +void util_symlink_destroy(eu_tabpage *pnode); +void util_updateui_msg(const eu_tabpage *pnode); +void util_updateui_icon(const HWND hwnd, const bool fnshow); +void util_updateui_titlebar(const HWND hwnd); +void util_update_env(eu_tabpage *pnode); +bool util_product_name(LPCWSTR filepath, LPWSTR out_string, size_t len); +bool util_file_access(LPCTSTR filename, uint32_t *pgranted); +bool util_get_unix_file_name(LPCWSTR path, wchar_t *out, const int len); +bool util_font_available(const char *name); +bool util_font_xy(const HWND hwnd, const HFONT hfont, int *px, int *py); wchar_t* util_get_nt_file_name(LPCWSTR path); const uint32_t util_os_version(void); const TCHAR* util_path_ext(const TCHAR *path); diff --git a/src/eu_view.c b/src/eu_view.c index 9f3f211f..6e9ba640 100644 --- a/src/eu_view.c +++ b/src/eu_view.c @@ -22,13 +22,14 @@ void on_view_filetree(void) { eu_get_config()->m_ftree_show ^= true; + on_treebar_size(); eu_window_resize(NULL); } void on_view_symtree(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod && (pnode->hwnd_symlist || pnode->hwnd_symtree)) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod && (pnode->hwnd_symlist || pnode->hwnd_symtree)) { if ((pnode->sym_show ^= true)) { @@ -41,7 +42,7 @@ on_view_symtree(eu_tabpage *pnode) void on_view_document_map(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { if ((pnode->map_show ^= true) && on_map_launch()) { @@ -52,9 +53,9 @@ on_view_document_map(eu_tabpage *pnode) } void -on_view_result_show(eu_tabpage *pnode, int key) +on_view_result_show(eu_tabpage *pnode, const int key) { - if (pnode && !pnode->hex_mode && !pnode->pmod && pnode->doc_ptr && pnode->doc_ptr->fn_keydown) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod && pnode->doc_ptr && pnode->doc_ptr->fn_keydown) { if (!pnode->result_show) { @@ -70,10 +71,10 @@ on_view_result_show(eu_tabpage *pnode, int key) } int -on_view_switch_type(int m_type) +on_view_switch_type(const int m_type) { eu_tabpage *pnode = on_tabpage_focus_at(); - if (pnode && !pnode->hex_mode && !pnode->pmod) + if (pnode && !TAB_HEX_MODE(pnode) && !pnode->pmod) { on_sci_resever_tab(pnode); if (m_type < 0) @@ -126,11 +127,15 @@ on_view_refresh_scroll(void) } } -static int -on_view_refresh_theme(HWND hwnd) +int +on_view_refresh_theme(HWND hwnd, const bool reload) { HWND snippet = NULL; on_dark_delete_theme_brush(); + if (reload && util_under_wine()) + { + on_theme_setup_font(hwnd); + } on_treebar_update_theme(); for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { @@ -139,7 +144,7 @@ on_view_refresh_theme(HWND hwnd) { break; } - if (p->hex_mode) + if (TAB_HEX_MODE(p)) { hexview_update_theme(p); } @@ -184,15 +189,20 @@ on_view_refresh_theme(HWND hwnd) on_snippet_reload(pview); } } - menu_bmp_destroy(); - on_view_refresh_scroll(); - SendMessage(hwnd, WM_SIZE, 0, 0); - UpdateWindowEx(hwnd); + if (reload) + { + menu_bmp_destroy(); + on_view_refresh_scroll(); + on_toolbar_redraw(hwnd); + on_splitter_redraw(); + SendMessage(hwnd, WM_SIZE, 0, 0); + UpdateWindowEx(hwnd); + } return SKYLARK_OK; } int -on_view_switch_theme(HWND hwnd, int id) +on_view_switch_theme(HWND hwnd, const int id) { int count = 0; HFONT hfont = NULL; @@ -236,7 +246,7 @@ on_view_switch_theme(HWND hwnd, int id) { eu_dark_theme_release(false); } - return on_view_refresh_theme(hwnd); + return on_view_refresh_theme(hwnd, true); } int @@ -250,7 +260,7 @@ on_view_modify_theme(void) eu_logmsg("%s: on_theme_setup_font failed\n", __FUNCTION__); return 1; } - return on_view_refresh_theme(hwnd); + return on_view_refresh_theme(hwnd, false); } return SKYLARK_OK; } @@ -319,7 +329,7 @@ on_view_tab_width(HWND hwnd, eu_tabpage *pnode) } for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { - if ((p = on_tabpage_get_ptr(index)) != NULL && !p->hex_mode && !p->pmod) + if ((p = on_tabpage_get_ptr(index)) != NULL && !TAB_HEX_MODE(p) && !p->pmod) { if (p->doc_ptr) { @@ -348,7 +358,7 @@ on_view_space_converter(HWND hwnd, eu_tabpage *pnode) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p != NULL && !p->hex_mode && !p->pmod) + if (p != NULL && !TAB_HEX_MODE(p) && !p->pmod) { if (p->doc_ptr) { @@ -395,7 +405,7 @@ on_view_light_fold(void) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { // 是否高亮显示当前折叠块 eu_sci_call(p, SCI_MARKERENABLEHIGHLIGHT, (sptr_t) eu_get_config()->light_fold, 0); } @@ -409,7 +419,7 @@ on_view_wrap_line(void) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { eu_sci_call(p, SCI_SETWRAPMODE, (eu_get_config()->line_mode ? 2 : 0), 0); } @@ -423,7 +433,7 @@ on_view_line_num(void) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { eu_sci_call(p, SCI_SETMARGINWIDTHN, MARGIN_LINENUMBER_INDEX, (eu_get_config()->m_linenumber ? MARGIN_LINENUMBER_WIDTH : 0)); } @@ -437,7 +447,7 @@ on_view_bookmark(void) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { eu_sci_call(p, SCI_SETMARGINWIDTHN, MARGIN_BOOKMARK_INDEX, (eu_get_config()->eu_bookmark.visable ? MARGIN_BOOKMARK_WIDTH : 0)); } @@ -450,7 +460,7 @@ on_view_update_fold(void) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && !p->pmod && p->doc_ptr && p->foldline) + if (p && !TAB_HEX_MODE(p) && !p->pmod && p->doc_ptr && p->foldline) { eu_sci_call(p, SCI_SETMARGINWIDTHN, MARGIN_FOLD_INDEX, eu_get_config()->block_fold ? MARGIN_FOLD_WIDTH : 0); } @@ -478,7 +488,7 @@ on_view_white_space(void) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { eu_sci_call(p, SCI_SETVIEWWS, (eu_get_config()->ws_visiable == true ? SCWS_VISIBLEALWAYS : SCWS_INVISIBLE), 0); } @@ -492,7 +502,7 @@ on_view_line_visiable(void) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { eu_sci_call(p, SCI_SETVIEWEOL, eu_get_config()->newline_visialbe, 0); } @@ -506,7 +516,7 @@ on_view_indent_visiable(void) for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { eu_tabpage *p = on_tabpage_get_ptr(index); - if (p && !p->hex_mode && !p->pmod) + if (p && !TAB_HEX_MODE(p) && !p->pmod) { eu_sci_call(p, SCI_SETINDENTATIONGUIDES, (eu_get_config()->m_indentation ? SC_IV_LOOKBOTH : SC_IV_NONE), 0); } @@ -527,7 +537,7 @@ on_view_history_visiable(eu_tabpage *pnode, const int wm_id) const uint32_t maskn = wm_id - IDM_VIEW_HISTORY_PLACEHOLDE; for (index = 0; index < count; ++index) { - if ((p = on_tabpage_get_ptr(index)) && !p->hex_mode && !p->pmod) + if ((p = on_tabpage_get_ptr(index)) && !TAB_HEX_MODE(p) && !p->pmod) { // 先给出提示 if (maskn > 1 && history_mask - IDM_VIEW_HISTORY_PLACEHOLDE == 1 && (eu_sci_call(p, SCI_CANUNDO, 0, 0) || eu_sci_call(p, SCI_CANREDO, 0, 0))) @@ -550,7 +560,7 @@ on_view_history_visiable(eu_tabpage *pnode, const int wm_id) eu_get_config()->history_mask = (uint32_t)wm_id; for (index = 0; index < count; ++index) { - if ((p = on_tabpage_get_ptr(index)) && !p->hex_mode && !p->pmod) + if ((p = on_tabpage_get_ptr(index)) && !TAB_HEX_MODE(p) && !p->pmod) { on_sci_update_history_margin(p); } @@ -618,7 +628,7 @@ on_view_zoom_reset(eu_tabpage *pnode) int on_view_editor_selection(eu_tabpage *pnode) { - if (!pnode || pnode->hex_mode || pnode->pmod) + if (!pnode || TAB_HEX_MODE(pnode) || pnode->pmod) { return SKYLARK_OK; } @@ -643,7 +653,7 @@ on_view_editor_selection(eu_tabpage *pnode) { flags |= SCFIND_WHOLEWORD; } - while (true) + while (found_pos >= 0) { found_pos = on_search_process_find(pnode, select_buf, start_pos, end_pos, flags); if (found_pos >= 0) @@ -655,10 +665,6 @@ on_view_editor_selection(eu_tabpage *pnode) start_pos = found_pos+select_len; ++pnode->match_count; } - else - { - break; - } } free(select_buf); } @@ -748,29 +754,28 @@ on_view_full_sreen(HWND hwnd) eu_get_config()->m_fullscreen ^= true; if (!eu_get_config()->m_fullscreen) { + int size = on_toolbar_icon_get(); eu_get_config()->m_menubar = true; - eu_get_config()->m_toolbar = g_toolbar_size > 0 ? g_toolbar_size : IDB_SIZE_1; + eu_get_config()->m_toolbar = size > 0 ? size : IDB_SIZE_1; + on_toolbar_set_height(size > 0 ? size : IDB_SIZE_1); eu_get_config()->m_statusbar = true; GetMenu(hwnd)?(void)0:SetMenu(hwnd, i18n_load_menu(IDC_SKYLARK)); - if (!GetDlgItem(hwnd, IDC_TOOLBAR)) - { - on_toolbar_create(hwnd); - } + on_toolbar_refresh(hwnd); } else { eu_get_config()->m_menubar = false; - g_toolbar_size = eu_get_config()->m_toolbar; + on_toolbar_icon_set(eu_get_config()->m_toolbar); eu_get_config()->m_toolbar = IDB_SIZE_0; eu_get_config()->m_statusbar = false; GetMenu(hwnd)?SetMenu(hwnd, NULL):(void)0; + } on_view_setfullscreenimpl(hwnd); - eu_window_resize(hwnd); } void -on_view_font_quality(HWND hwnd, int res_id) +on_view_font_quality(HWND hwnd, const int res_id) { int old_id = eu_get_config()->m_quality; if (eu_get_config()->m_quality != res_id) @@ -780,23 +785,25 @@ on_view_font_quality(HWND hwnd, int res_id) { eu_logmsg("%s: on_theme_setup_font return false\n", __FUNCTION__); eu_get_config()->m_quality = old_id; - return; } - for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) + else { - eu_tabpage *p = on_tabpage_get_ptr(index); - if (p) + for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { - on_sci_init_style(p); - on_sci_after_file(p, false); + eu_tabpage *p = on_tabpage_get_ptr(index); + if (p) + { + on_sci_init_style(p); + on_sci_after_file(p, false); + } } + eu_window_resize(hwnd); } - eu_window_resize(hwnd); } } void -on_view_enable_rendering(HWND hwnd, int res_id) +on_view_enable_rendering(HWND hwnd, const int res_id) { if (!util_under_wine() && eu_get_config()->m_render != res_id) { diff --git a/src/eu_view.h b/src/eu_view.h index 912a0891..5d8f6763 100644 --- a/src/eu_view.h +++ b/src/eu_view.h @@ -26,8 +26,9 @@ extern "C" { #endif -int on_view_switch_type(int type); -int on_view_switch_theme(HWND hwnd, int id); +int on_view_switch_type(const int type); +int on_view_refresh_theme(HWND hwnd, const bool reload); +int on_view_switch_theme(HWND hwnd, const int id); int on_view_modify_theme(void); int on_view_editor_selection(eu_tabpage *pnode); void on_view_filetree(void); @@ -45,7 +46,7 @@ void on_view_light_str(eu_tabpage *p); void on_view_light_brace(eu_tabpage *p); void on_view_light_fold(void); void on_view_identation(void); -void on_view_result_show(eu_tabpage *pnode, int key); +void on_view_result_show(eu_tabpage *pnode, const int key); void on_view_copy_theme(void); void on_view_tab_width(HWND hwnd, eu_tabpage *pnode); void on_view_space_converter(HWND hwnd, eu_tabpage *pnode); @@ -54,8 +55,8 @@ void on_view_zoom_in(eu_tabpage *pnode); void on_view_zoom_reset(eu_tabpage *pnode); void on_view_setfullscreenimpl(HWND hwnd); void on_view_full_sreen(HWND hwnd); -void on_view_font_quality(HWND hwnd, int res_id); -void on_view_enable_rendering(HWND hwnd, int res_id); +void on_view_font_quality(HWND hwnd, const int res_id); +void on_view_enable_rendering(HWND hwnd, const int res_id); #ifdef __cplusplus } diff --git a/src/targetver.h b/src/targetver.h index 0a98a34c..3633ca94 100644 --- a/src/targetver.h +++ b/src/targetver.h @@ -30,7 +30,7 @@ // 定义版本信息 #define __EU_INFO_VERSION 4 #define __EU_INFO_VERSION_MINOR 0 -#define __EU_INFO_VERSION_PATCHLEVEL 7 +#define __EU_INFO_VERSION_PATCHLEVEL 8 #define __ORIGINAL_NAME TEXT("skylark.exe") #if !__EU_INFO_VERSION_PATCHLEVEL @@ -196,7 +196,8 @@ #define IDM_OTHER_3 10064 #define IDM_OTHER_ANSI 10065 #define IDM_OTHER_BIN 10066 -#define IDM_UNKNOWN 10067 +#define IDM_OTHER_PLUGIN 10067 +#define IDM_UNKNOWN 10068 #define IDM_LBREAK_1 10080 #define IDM_LBREAK_2 10081 @@ -502,6 +503,7 @@ #define IDM_SCRIPT_EXEC 30025 #define IDM_CMD_TAB 30026 #define IDC_TOOLBAR 30027 +#define IDM_FILE_UNMODIFIED 30028 #define IDB_SIZE_0 30030 #define IDB_SIZE_1 30031 @@ -546,6 +548,11 @@ #define IDM_EDIT_3DES_CBC_DECRYPTO 30206 #define IDM_VIEW_BOOKMARK_VISIABLE 30207 #define IDM_SEARCH_REMOVE_ALL_BOOKMARKS 30210 +#define IDM_EDIT_BOOKMARK_LINES_COPY 30211 +#define IDM_EDIT_BOOKMARK_LINES_CUT 30212 +#define IDM_EDIT_BOOKMARK_LINES_REMOVE 30213 +#define IDM_EDIT_BOOKMARK_LINES_RESERVE 30214 +#define IDM_EDIT_GOLINE_GROUP 30215 #define IDM_VIEW_INDENTGUIDES_VISIABLE 30300 #define IDM_SEARCH_GOTO_PREV_BOOKMARK_INALL 30301 @@ -624,6 +631,7 @@ #define IDM_EDIT_CLEAR_CLIPBOARD 30456 #define IDM_EDIT_COPY_INCREMENTAL 30457 #define IDM_EDIT_COPY_RTF 30458 +#define IDM_VIEW_TABBAR_SPLIT 30459 #define IDM_VIEW_WHITESPACE_VISIABLE 30500 #define IDM_VIEW_LINENUMBER_VISIABLE 30501 @@ -941,6 +949,7 @@ #define IDM_EDIT_LINECOMMENT 42043 #define IDM_EDIT_STREAMCOMMENT 42044 #define IDM_VIEW_HIGHLIGHT_BRACE 42045 +#define IDM_VIEW_HIGHLIGHT_GROUP 42046 // Page Setup // based on prnsetup.dlg from Windows SDK diff --git a/src/version_display.txt b/src/version_display.txt index 43beb400..a2cec7af 100644 --- a/src/version_display.txt +++ b/src/version_display.txt @@ -1 +1 @@ -4.0.7 +4.0.8