From aed8ce9da277f5ecffe968b324f242c41c3b752a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 10:50:31 +0200 Subject: Adding upstream version 2:9.0.1378. Signed-off-by: Daniel Baumann --- src/GvimExt/GvimExt.reg | 20 + src/GvimExt/Make_ming.mak | 83 + src/GvimExt/Make_mvc.mak | 98 + src/GvimExt/Makefile | 4 + src/GvimExt/README.txt | 94 + src/GvimExt/gvimext.cpp | 970 ++ src/GvimExt/gvimext.def | 8 + src/GvimExt/gvimext.h | 168 + src/GvimExt/gvimext.inf | 22 + src/GvimExt/gvimext.rc | 109 + src/GvimExt/gvimext_ming.def | 10 + src/GvimExt/gvimext_ming.rc | 45 + src/GvimExt/resource.h | 15 + src/GvimExt/uninst.bat | 1 + src/INSTALL | 221 + src/INSTALLami.txt | 19 + src/INSTALLmac.txt | 83 + src/INSTALLpc.txt | 998 ++ src/INSTALLvms.txt | 390 + src/INSTALLx.txt | 156 + src/Make_all.mak | 16 + src/Make_ami.mak | 202 + src/Make_cyg.mak | 53 + src/Make_cyg_ming.mak | 1383 ++ src/Make_ming.mak | 51 + src/Make_mvc.mak | 1946 +++ src/Make_vms.mms | 1260 ++ src/Makefile | 4467 +++++ src/README.md | 235 + src/alloc.c | 894 + src/alloc.h | 49 + src/arabic.c | 396 + src/arglist.c | 1496 ++ src/ascii.h | 92 + src/auto/configure | 16382 +++++++++++++++++++ src/autocmd.c | 3274 ++++ src/beval.c | 356 + src/beval.h | 95 + src/bigvim.bat | 5 + src/bigvim64.bat | 7 + src/blob.c | 853 + src/blowfish.c | 688 + src/buffer.c | 6058 +++++++ src/bufwrite.c | 2638 +++ src/change.c | 2392 +++ src/channel.c | 5314 ++++++ src/charset.c | 2411 +++ src/cindent.c | 4179 +++++ src/clientserver.c | 1050 ++ src/clipboard.c | 2227 +++ src/cmdexpand.c | 4063 +++++ src/cmdhist.c | 785 + src/config.h.in | 501 + src/config.mk.dist | 5 + src/config.mk.in | 186 + src/configure | 10 + src/configure.ac | 4646 ++++++ src/create_cmdidxs.vim | 104 + src/create_nvcmdidxs.c | 38 + src/create_nvcmdidxs.vim | 60 + src/crypt.c | 1163 ++ src/crypt_zip.c | 157 + src/debugger.c | 1057 ++ src/dict.c | 1620 ++ src/diff.c | 3439 ++++ src/digraph.c | 2408 +++ src/dlldata.c | 38 + src/dosinst.c | 2811 ++++ src/dosinst.h | 516 + src/drawline.c | 4099 +++++ src/drawscreen.c | 3352 ++++ src/edit.c | 5426 ++++++ src/errors.h | 3457 ++++ src/eval.c | 7503 +++++++++ src/evalbuffer.c | 1020 ++ src/evalfunc.c | 10805 ++++++++++++ src/evalvars.c | 5019 ++++++ src/evalwindow.c | 1447 ++ src/ex_cmdidxs.h | 72 + src/ex_cmds.c | 5610 +++++++ src/ex_cmds.h | 1968 +++ src/ex_cmds2.c | 998 ++ src/ex_docmd.c | 9830 +++++++++++ src/ex_eval.c | 2627 +++ src/ex_getln.c | 4857 ++++++ src/feature.h | 1165 ++ src/fileio.c | 5708 +++++++ src/filepath.c | 4300 +++++ src/findfile.c | 2781 ++++ src/float.c | 589 + src/fold.c | 3846 +++++ src/getchar.c | 4047 +++++ src/globals.h | 2056 +++ src/gui.c | 5536 +++++++ src/gui.h | 555 + src/gui_beval.c | 1180 ++ src/gui_dwrite.cpp | 1355 ++ src/gui_dwrite.h | 92 + src/gui_gtk.c | 2692 +++ src/gui_gtk_f.c | 883 + src/gui_gtk_f.h | 80 + src/gui_gtk_res.xml | 18 + src/gui_gtk_vms.h | 730 + src/gui_gtk_x11.c | 7312 +++++++++ src/gui_haiku.cc | 5094 ++++++ src/gui_haiku.h | 51 + src/gui_motif.c | 3907 +++++ src/gui_photon.c | 2989 ++++ src/gui_w32.c | 8827 ++++++++++ src/gui_w32_rc.h | 8 + src/gui_x11.c | 3304 ++++ src/gui_x11_pm.h | 92 + src/gui_xim.c | 1838 +++ src/gui_xmdlg.c | 1279 ++ src/gui_xmebw.c | 1460 ++ src/gui_xmebw.h | 72 + src/gui_xmebwp.h | 88 + src/gvimtutor | 8 + src/hardcopy.c | 3461 ++++ src/hashtab.c | 513 + src/help.c | 1330 ++ src/highlight.c | 4577 ++++++ src/if_cscope.c | 2546 +++ src/if_lua.c | 2800 ++++ src/if_mzsch.c | 3883 +++++ src/if_mzsch.h | 76 + src/if_ole.cpp | 796 + src/if_ole.h | 290 + src/if_ole.idl | 45 + src/if_perl.xs | 1994 +++ src/if_perlsfio.c | 66 + src/if_py_both.h | 6992 ++++++++ src/if_python.c | 1552 ++ src/if_python3.c | 1952 +++ src/if_ruby.c | 1928 +++ src/if_tcl.c | 2120 +++ src/if_xcmdsrv.c | 1542 ++ src/iid_ole.c | 57 + src/indent.c | 2282 +++ src/insexpand.c | 5186 ++++++ src/install-sh | 501 + src/installman.sh | 125 + src/installml.sh | 170 + src/iscygpty.c | 188 + src/iscygpty.h | 41 + src/job.c | 2026 +++ src/json.c | 1277 ++ src/json_test.c | 203 + src/keymap.h | 525 + src/kword_test.c | 82 + src/libvterm/.bzrignore | 13 + src/libvterm/.gitignore | 17 + src/libvterm/CONTRIBUTING | 22 + src/libvterm/LICENSE | 23 + src/libvterm/Makefile | 142 + src/libvterm/README | 39 + src/libvterm/doc/URLs | 14 + src/libvterm/doc/seqs.txt | 283 + src/libvterm/find-wide-chars.pl | 30 + src/libvterm/include/vterm.h | 671 + src/libvterm/include/vterm_keycodes.h | 64 + src/libvterm/src/encoding.c | 234 + src/libvterm/src/encoding/DECdrawing.inc | 136 + src/libvterm/src/encoding/DECdrawing.tbl | 31 + src/libvterm/src/encoding/uk.inc | 136 + src/libvterm/src/encoding/uk.tbl | 1 + src/libvterm/src/fullwidth.inc | 111 + src/libvterm/src/keyboard.c | 259 + src/libvterm/src/mouse.c | 101 + src/libvterm/src/parser.c | 404 + src/libvterm/src/pen.c | 629 + src/libvterm/src/rect.h | 56 + src/libvterm/src/screen.c | 1206 ++ src/libvterm/src/state.c | 2473 +++ src/libvterm/src/unicode.c | 587 + src/libvterm/src/utf8.h | 47 + src/libvterm/src/vterm.c | 451 + src/libvterm/src/vterm_internal.h | 329 + src/libvterm/t/02parser.test | 266 + src/libvterm/t/03encoding_utf8.test | 122 + src/libvterm/t/10state_putglyph.test | 74 + src/libvterm/t/11state_movecursor.test | 224 + src/libvterm/t/12state_scroll.test | 156 + src/libvterm/t/13state_edit.test | 304 + src/libvterm/t/14state_encoding.test | 105 + src/libvterm/t/15state_mode.test | 86 + src/libvterm/t/16state_resize.test | 48 + src/libvterm/t/17state_mouse.test | 181 + src/libvterm/t/18state_termprops.test | 42 + src/libvterm/t/20state_wrapping.test | 69 + src/libvterm/t/21state_tabstops.test | 60 + src/libvterm/t/22state_save.test | 64 + src/libvterm/t/25state_input.test | 155 + src/libvterm/t/26state_query.test | 67 + src/libvterm/t/27state_reset.test | 32 + src/libvterm/t/28state_dbl_wh.test | 61 + src/libvterm/t/29state_fallback.test | 31 + src/libvterm/t/30state_pen.test | 125 + src/libvterm/t/31state_rep.test | 128 + src/libvterm/t/32state_flow.test | 28 + src/libvterm/t/40state_selection.test | 55 + src/libvterm/t/60screen_ascii.test | 69 + src/libvterm/t/61screen_unicode.test | 47 + src/libvterm/t/62screen_damage.test | 155 + src/libvterm/t/63screen_resize.test | 117 + src/libvterm/t/64screen_pen.test | 61 + src/libvterm/t/65screen_protect.test | 16 + src/libvterm/t/66screen_extent.test | 11 + src/libvterm/t/67screen_dbl_wh.test | 38 + src/libvterm/t/68screen_termprops.test | 17 + src/libvterm/t/69screen_reflow.test | 79 + src/libvterm/t/90vttest_01-movement-1.test | 87 + src/libvterm/t/90vttest_01-movement-2.test | 40 + src/libvterm/t/90vttest_01-movement-3.test | 21 + src/libvterm/t/90vttest_01-movement-4.test | 36 + src/libvterm/t/90vttest_02-screen-1.test | 18 + src/libvterm/t/90vttest_02-screen-2.test | 29 + src/libvterm/t/90vttest_02-screen-3.test | 16 + src/libvterm/t/90vttest_02-screen-4.test | 17 + src/libvterm/t/92lp1640917.test | 13 + src/libvterm/t/harness.c | 1233 ++ src/libvterm/t/run-test.pl | 233 + src/libvterm/tbl2inc_c.pl | 51 + src/libvterm/vterm.pc.in | 8 + src/link.390 | 7 + src/link.sh | 151 + src/list.c | 3151 ++++ src/locale.c | 563 + src/logfile.c | 210 + src/macros.h | 398 + src/main.c | 3722 +++++ src/map.c | 3203 ++++ src/mark.c | 1507 ++ src/match.c | 1456 ++ src/mbyte.c | 5785 +++++++ src/memfile.c | 1501 ++ src/memfile_test.c | 143 + src/memline.c | 6018 +++++++ src/menu.c | 3034 ++++ src/message.c | 4422 +++++ src/message_test.c | 327 + src/misc1.c | 2811 ++++ src/misc2.c | 3065 ++++ src/mouse.c | 3275 ++++ src/move.c | 3633 ++++ src/msvc-latest.bat | 72 + src/msvc2015.bat | 15 + src/msvc2017.bat | 13 + src/msvc2019.bat | 13 + src/msvc2022.bat | 13 + src/msys32.bat | 6 + src/msys64.bat | 6 + src/mysign | 1 + src/nbdebug.c | 168 + src/nbdebug.h | 73 + src/netbeans.c | 3489 ++++ src/normal.c | 7465 +++++++++ src/nv_cmdidxs.h | 209 + src/nv_cmds.h | 311 + src/ops.c | 4343 +++++ src/option.c | 8193 ++++++++++ src/option.h | 1315 ++ src/optiondefs.h | 3006 ++++ src/optionstr.c | 3364 ++++ src/os_amiga.c | 1770 ++ src/os_amiga.h | 237 + src/os_dos.h | 135 + src/os_haiku.h | 37 + src/os_haiku.rdef.in | 142 + src/os_mac.h | 318 + src/os_mac_conv.c | 597 + src/os_macosx.m | 524 + src/os_mswin.c | 3101 ++++ src/os_qnx.c | 155 + src/os_qnx.h | 19 + src/os_unix.c | 8488 ++++++++++ src/os_unix.h | 486 + src/os_unixx.h | 116 + src/os_vms.c | 853 + src/os_vms_conf.h | 210 + src/os_vms_fix.com | 276 + src/os_vms_mms.c | 77 + src/os_w32dll.c | 27 + src/os_w32exe.c | 51 + src/os_win32.c | 9010 ++++++++++ src/os_win32.h | 225 + src/osdef.sh | 100 + src/osdef1.h.in | 138 + src/osdef2.h.in | 100 + src/pathdef.sh | 11 + src/po/Make_all.mak | 182 + src/po/Make_cyg.mak | 105 + src/po/Make_ming.mak | 128 + src/po/Make_mvc.mak | 102 + src/po/Makefile | 243 + src/po/README.txt | 157 + src/po/README_mingw.txt | 105 + src/po/README_mvc.txt | 119 + src/po/af.po | 4432 +++++ src/po/ca.po | 10277 ++++++++++++ src/po/check.vim | 225 + src/po/cleanup.vim | 34 + src/po/cs.cp1250.po | 4667 ++++++ src/po/cs.po | 4667 ++++++ src/po/da.po | 7202 ++++++++ src/po/de.po | 10210 ++++++++++++ src/po/en_GB.po | 376 + src/po/eo.po | 8599 ++++++++++ src/po/es.po | 10221 ++++++++++++ src/po/fi.po | 10017 ++++++++++++ src/po/fixfilenames.vim | 13 + src/po/fr.po | 8355 ++++++++++ src/po/ga.po | 9994 +++++++++++ src/po/gvim.desktop.in | 80 + src/po/it.po | 9341 +++++++++++ src/po/ja.euc-jp.po | 9985 +++++++++++ src/po/ja.po | 9985 +++++++++++ src/po/ja.sjis.po | 9985 +++++++++++ src/po/ko.UTF-8.po | 7107 ++++++++ src/po/ko.po | 7107 ++++++++ src/po/lv.po | 286 + src/po/nb.po | 6212 +++++++ src/po/nl.po | 5891 +++++++ src/po/no.po | 6212 +++++++ src/po/pl.UTF-8.po | 6962 ++++++++ src/po/pl.cp1250.po | 6962 ++++++++ src/po/pl.po | 6962 ++++++++ src/po/pt_BR.po | 7117 ++++++++ src/po/ru.cp1251.po | 10159 ++++++++++++ src/po/ru.po | 10159 ++++++++++++ src/po/sjiscorr.c | 48 + src/po/sk.cp1250.po | 5840 +++++++ src/po/sk.po | 5840 +++++++ src/po/sr.po | 10342 ++++++++++++ src/po/sv.po | 6195 +++++++ src/po/tojavascript.vim | 18 + src/po/tr.po | 9942 +++++++++++ src/po/uk.cp1251.po | 10210 ++++++++++++ src/po/uk.po | 10210 ++++++++++++ src/po/vi.po | 5232 ++++++ src/po/vim.desktop.in | 80 + src/po/zh_CN.UTF-8.po | 9835 +++++++++++ src/po/zh_CN.cp936.po | 9835 +++++++++++ src/po/zh_CN.po | 9835 +++++++++++ src/po/zh_TW.UTF-8.po | 5307 ++++++ src/po/zh_TW.po | 5300 ++++++ src/popupmenu.c | 1633 ++ src/popupwin.c | 4701 ++++++ src/profiler.c | 1110 ++ src/proto.h | 344 + src/proto/alloc.pro | 31 + src/proto/arabic.pro | 5 + src/proto/arglist.pro | 33 + src/proto/autocmd.pro | 47 + src/proto/beval.pro | 7 + src/proto/blob.pro | 29 + src/proto/blowfish.pro | 6 + src/proto/buffer.pro | 73 + src/proto/bufwrite.pro | 4 + src/proto/change.pro | 33 + src/proto/channel.pro | 58 + src/proto/charset.pro | 73 + src/proto/cindent.pro | 11 + src/proto/clientserver.pro | 16 + src/proto/clipboard.pro | 38 + src/proto/cmdexpand.pro | 22 + src/proto/cmdhist.pro | 19 + src/proto/crypt.pro | 31 + src/proto/crypt_zip.pro | 5 + src/proto/debugger.pro | 15 + src/proto/dict.pro | 52 + src/proto/diff.pro | 33 + src/proto/digraph.pro | 15 + src/proto/drawline.pro | 4 + src/proto/drawscreen.pro | 27 + src/proto/edit.pro | 42 + src/proto/eval.pro | 86 + src/proto/evalbuffer.pro | 27 + src/proto/evalfunc.pro | 30 + src/proto/evalvars.pro | 111 + src/proto/evalwindow.pro | 41 + src/proto/ex_cmds.pro | 44 + src/proto/ex_cmds2.pro | 18 + src/proto/ex_docmd.pro | 75 + src/proto/ex_eval.pro | 39 + src/proto/ex_getln.pro | 46 + src/proto/fileio.pro | 44 + src/proto/filepath.pro | 64 + src/proto/findfile.pro | 19 + src/proto/float.pro | 29 + src/proto/fold.pro | 45 + src/proto/getchar.pro | 58 + src/proto/gui.pro | 68 + src/proto/gui_beval.pro | 9 + src/proto/gui_gtk.pro | 24 + src/proto/gui_gtk_gresources.pro | 5 + src/proto/gui_gtk_x11.pro | 81 + src/proto/gui_haiku.pro | 97 + src/proto/gui_motif.pro | 46 + src/proto/gui_photon.pro | 72 + src/proto/gui_w32.pro | 100 + src/proto/gui_x11.pro | 72 + src/proto/gui_xim.pro | 21 + src/proto/gui_xmdlg.pro | 3 + src/proto/hardcopy.pro | 20 + src/proto/hashtab.pro | 16 + src/proto/help.pro | 13 + src/proto/highlight.pro | 49 + src/proto/if_cscope.pro | 12 + src/proto/if_lua.pro | 12 + src/proto/if_mzsch.pro | 17 + src/proto/if_ole.pro | 5 + src/proto/if_perl.pro | 9 + src/proto/if_perlsfio.pro | 3 + src/proto/if_python.pro | 13 + src/proto/if_python3.pro | 13 + src/proto/if_ruby.pro | 11 + src/proto/if_tcl.pro | 11 + src/proto/if_xcmdsrv.pro | 13 + src/proto/indent.pro | 38 + src/proto/insexpand.pro | 62 + src/proto/job.pro | 37 + src/proto/json.pro | 11 + src/proto/list.pro | 67 + src/proto/locale.pro | 9 + src/proto/logfile.pro | 7 + src/proto/main.pro | 18 + src/proto/map.pro | 35 + src/proto/mark.pro | 31 + src/proto/match.pro | 17 + src/proto/mbyte.pro | 91 + src/proto/memfile.pro | 18 + src/proto/memline.pro | 42 + src/proto/menu.pro | 27 + src/proto/message.pro | 80 + src/proto/misc1.pro | 56 + src/proto/misc2.pro | 64 + src/proto/mouse.pro | 26 + src/proto/move.pro | 51 + src/proto/netbeans.pro | 28 + src/proto/normal.pro | 34 + src/proto/ops.pro | 24 + src/proto/option.pro | 150 + src/proto/optionstr.pro | 126 + src/proto/os_amiga.pro | 46 + src/proto/os_mac_conv.pro | 12 + src/proto/os_macosx.pro | 7 + src/proto/os_mswin.pro | 54 + src/proto/os_qnx.pro | 8 + src/proto/os_unix.pro | 91 + src/proto/os_vms.pro | 16 + src/proto/os_win32.pro | 90 + src/proto/popupmenu.pro | 20 + src/proto/popupwin.pro | 76 + src/proto/profiler.pro | 35 + src/proto/pty.pro | 5 + src/proto/quickfix.pro | 43 + src/proto/regexp.pro | 27 + src/proto/register.pro | 42 + src/proto/screen.pro | 61 + src/proto/scriptfile.pro | 50 + src/proto/search.pro | 46 + src/proto/session.pro | 8 + src/proto/sha256.pro | 9 + src/proto/sign.pro | 33 + src/proto/sound.pro | 14 + src/proto/spell.pro | 50 + src/proto/spellfile.pro | 9 + src/proto/spellsuggest.pro | 5 + src/proto/strings.pro | 49 + src/proto/syntax.pro | 24 + src/proto/tag.pro | 17 + src/proto/term.pro | 96 + src/proto/terminal.pro | 74 + src/proto/termlib.pro | 8 + src/proto/testing.pro | 39 + src/proto/textformat.pro | 11 + src/proto/textobject.pro | 15 + src/proto/textprop.pro | 28 + src/proto/time.pro | 30 + src/proto/typval.pro | 85 + src/proto/ui.pro | 37 + src/proto/undo.pro | 32 + src/proto/usercmd.pro | 24 + src/proto/userfunc.pro | 97 + src/proto/version.pro | 10 + src/proto/vim9class.pro | 18 + src/proto/vim9cmds.pro | 37 + src/proto/vim9compile.pro | 35 + src/proto/vim9execute.pro | 29 + src/proto/vim9expr.pro | 18 + src/proto/vim9instr.pro | 85 + src/proto/vim9script.pro | 23 + src/proto/vim9type.pro | 38 + src/proto/viminfo.pro | 8 + src/proto/winclip.pro | 15 + src/proto/window.pro | 93 + src/protodef.h | 18 + src/pty.c | 446 + src/quickfix.c | 8637 ++++++++++ src/regexp.c | 3082 ++++ src/regexp.h | 189 + src/regexp_bt.c | 5598 +++++++ src/regexp_nfa.c | 7648 +++++++++ src/register.c | 3052 ++++ src/screen.c | 4978 ++++++ src/scriptfile.c | 2767 ++++ src/search.c | 5063 ++++++ src/session.c | 1445 ++ src/sha256.c | 427 + src/sign.c | 2891 ++++ src/sound.c | 524 + src/spell.c | 4451 +++++ src/spell.h | 319 + src/spellfile.c | 6712 ++++++++ src/spellsuggest.c | 4518 +++++ src/strings.c | 2967 ++++ src/structs.h | 4846 ++++++ src/syntax.c | 6790 ++++++++ src/tag.c | 4698 ++++++ src/tearoff.bmp | Bin 0 -> 118 bytes src/tee/Make_ming.mak | 21 + src/tee/Make_mvc.mak | 19 + src/tee/Makefile | 2 + src/tee/tee.c | 165 + src/term.c | 7517 +++++++++ src/termdefs.h | 231 + src/terminal.c | 7710 +++++++++ src/termlib.c | 633 + src/testdir/Make_all.mak | 555 + src/testdir/Make_amiga.mak | 35 + src/testdir/Make_dos.mak | 4 + src/testdir/Make_ming.mak | 168 + src/testdir/Make_mvc.mak | 162 + src/testdir/Make_vms.mms | 108 + src/testdir/Makefile | 176 + src/testdir/README.txt | 121 + src/testdir/amiga.vim | 6 + src/testdir/check.vim | 286 + src/testdir/color_ramp.vim | 85 + src/testdir/dos.vim | 9 + src/testdir/dotest.in | 3 + src/testdir/dumps/Test_Xcursorline_1.dump | 20 + src/testdir/dumps/Test_Xcursorline_10.dump | 20 + src/testdir/dumps/Test_Xcursorline_11.dump | 20 + src/testdir/dumps/Test_Xcursorline_12.dump | 20 + src/testdir/dumps/Test_Xcursorline_13.dump | 20 + src/testdir/dumps/Test_Xcursorline_14.dump | 20 + src/testdir/dumps/Test_Xcursorline_15.dump | 20 + src/testdir/dumps/Test_Xcursorline_16.dump | 20 + src/testdir/dumps/Test_Xcursorline_17.dump | 20 + src/testdir/dumps/Test_Xcursorline_18.dump | 20 + src/testdir/dumps/Test_Xcursorline_19.dump | 20 + src/testdir/dumps/Test_Xcursorline_2.dump | 20 + src/testdir/dumps/Test_Xcursorline_20.dump | 20 + src/testdir/dumps/Test_Xcursorline_21.dump | 20 + src/testdir/dumps/Test_Xcursorline_22.dump | 20 + src/testdir/dumps/Test_Xcursorline_23.dump | 20 + src/testdir/dumps/Test_Xcursorline_24.dump | 20 + src/testdir/dumps/Test_Xcursorline_3.dump | 20 + src/testdir/dumps/Test_Xcursorline_4.dump | 20 + src/testdir/dumps/Test_Xcursorline_5.dump | 20 + src/testdir/dumps/Test_Xcursorline_6.dump | 20 + src/testdir/dumps/Test_Xcursorline_7.dump | 20 + src/testdir/dumps/Test_Xcursorline_8.dump | 20 + src/testdir/dumps/Test_Xcursorline_9.dump | 20 + src/testdir/dumps/Test_appendbufline_1.dump | 10 + src/testdir/dumps/Test_autocmd_nested_switch.dump | 10 + src/testdir/dumps/Test_balloon_eval_term_01.dump | 10 + src/testdir/dumps/Test_balloon_eval_term_01a.dump | 10 + src/testdir/dumps/Test_balloon_eval_term_02.dump | 10 + src/testdir/dumps/Test_changing_cmdheight_1.dump | 8 + src/testdir/dumps/Test_changing_cmdheight_2.dump | 8 + src/testdir/dumps/Test_changing_cmdheight_3.dump | 8 + src/testdir/dumps/Test_changing_cmdheight_4.dump | 8 + src/testdir/dumps/Test_changing_cmdheight_5.dump | 8 + src/testdir/dumps/Test_changing_cmdheight_6.dump | 8 + src/testdir/dumps/Test_cmdheight_tabline_1.dump | 6 + src/testdir/dumps/Test_cmdlineclear_tabenter.dump | 10 + src/testdir/dumps/Test_cmdwin_interrupted.dump | 18 + src/testdir/dumps/Test_cmdwin_no_terminal.dump | 12 + src/testdir/dumps/Test_cmdwin_restore_1.dump | 12 + src/testdir/dumps/Test_cmdwin_restore_2.dump | 12 + src/testdir/dumps/Test_cmdwin_restore_3.dump | 18 + src/testdir/dumps/Test_cmdwin_wrong_command_1.dump | 12 + src/testdir/dumps/Test_cmdwin_wrong_command_2.dump | 12 + src/testdir/dumps/Test_colorcolumn_1.dump | 10 + src/testdir/dumps/Test_colorcolumn_2.dump | 10 + src/testdir/dumps/Test_colorcolumn_3.dump | 10 + src/testdir/dumps/Test_conceal_cuc_01.dump | 10 + src/testdir/dumps/Test_conceal_cuc_02.dump | 10 + src/testdir/dumps/Test_conceal_cul_01.dump | 20 + src/testdir/dumps/Test_conceal_cul_02.dump | 20 + src/testdir/dumps/Test_conceal_cul_03.dump | 20 + src/testdir/dumps/Test_conceal_linebreak_1.dump | 8 + src/testdir/dumps/Test_conceal_resize_01.dump | 6 + src/testdir/dumps/Test_conceal_resize_02.dump | 7 + src/testdir/dumps/Test_conceal_two_windows_01.dump | 20 + src/testdir/dumps/Test_conceal_two_windows_02.dump | 20 + src/testdir/dumps/Test_conceal_two_windows_03.dump | 20 + src/testdir/dumps/Test_conceal_two_windows_04.dump | 20 + src/testdir/dumps/Test_conceal_two_windows_05.dump | 20 + .../dumps/Test_conceal_two_windows_06c.dump | 20 + .../dumps/Test_conceal_two_windows_06i.dump | 20 + .../dumps/Test_conceal_two_windows_06n.dump | 20 + .../dumps/Test_conceal_two_windows_06v.dump | 20 + .../dumps/Test_conceal_two_windows_07c.dump | 20 + .../dumps/Test_conceal_two_windows_07i.dump | 20 + .../dumps/Test_conceal_two_windows_07in.dump | 20 + .../dumps/Test_conceal_two_windows_07n.dump | 20 + .../dumps/Test_conceal_two_windows_07v.dump | 20 + .../dumps/Test_conceal_two_windows_08c.dump | 20 + .../dumps/Test_conceal_two_windows_08i.dump | 20 + .../dumps/Test_conceal_two_windows_08n.dump | 20 + .../dumps/Test_conceal_two_windows_08v.dump | 20 + .../dumps/Test_conceal_two_windows_09c.dump | 20 + .../dumps/Test_conceal_two_windows_09i.dump | 20 + .../dumps/Test_conceal_two_windows_09n.dump | 20 + .../dumps/Test_conceal_two_windows_09v.dump | 20 + src/testdir/dumps/Test_conceal_two_windows_10.dump | 20 + src/testdir/dumps/Test_conceal_two_windows_11.dump | 20 + src/testdir/dumps/Test_conceal_two_windows_12.dump | 20 + src/testdir/dumps/Test_conceal_two_windows_13.dump | 20 + .../dumps/Test_cursor_position_with_showbreak.dump | 6 + .../dumps/Test_cursorcolumn_callback_1.dump | 8 + .../dumps/Test_cursorcolumn_insert_on_tab_1.dump | 8 + .../dumps/Test_cursorcolumn_insert_on_tab_2.dump | 8 + .../dumps/Test_cursorcolumn_insert_on_tab_3.dump | 8 + src/testdir/dumps/Test_cursorline_callback_1.dump | 8 + src/testdir/dumps/Test_cursorline_redraw_1.dump | 20 + src/testdir/dumps/Test_cursorline_redraw_2.dump | 20 + .../dumps/Test_cursorline_screenline_1.dump | 8 + .../dumps/Test_cursorline_screenline_2.dump | 8 + .../dumps/Test_cursorline_with_visualmode_01.dump | 12 + src/testdir/dumps/Test_cursorline_yank_01.dump | 8 + src/testdir/dumps/Test_diff_01.dump | 20 + src/testdir/dumps/Test_diff_02.dump | 20 + src/testdir/dumps/Test_diff_03.dump | 20 + src/testdir/dumps/Test_diff_04.dump | 20 + src/testdir/dumps/Test_diff_05.dump | 20 + src/testdir/dumps/Test_diff_06.0.dump | 20 + src/testdir/dumps/Test_diff_06.1.dump | 20 + src/testdir/dumps/Test_diff_06.2.dump | 20 + src/testdir/dumps/Test_diff_06.dump | 20 + src/testdir/dumps/Test_diff_07.dump | 20 + src/testdir/dumps/Test_diff_08.dump | 20 + src/testdir/dumps/Test_diff_09.dump | 20 + src/testdir/dumps/Test_diff_10.dump | 20 + src/testdir/dumps/Test_diff_11.dump | 20 + src/testdir/dumps/Test_diff_12.dump | 20 + src/testdir/dumps/Test_diff_13.dump | 20 + src/testdir/dumps/Test_diff_14.dump | 20 + src/testdir/dumps/Test_diff_15.dump | 20 + src/testdir/dumps/Test_diff_16.dump | 20 + src/testdir/dumps/Test_diff_17.dump | 20 + src/testdir/dumps/Test_diff_18.dump | 20 + src/testdir/dumps/Test_diff_19.dump | 20 + src/testdir/dumps/Test_diff_20.dump | 20 + src/testdir/dumps/Test_diff_bin_01.dump | 20 + src/testdir/dumps/Test_diff_bin_02.dump | 20 + src/testdir/dumps/Test_diff_bin_03.dump | 20 + src/testdir/dumps/Test_diff_bin_04.dump | 20 + src/testdir/dumps/Test_diff_cuc_01.dump | 20 + src/testdir/dumps/Test_diff_cuc_02.dump | 20 + src/testdir/dumps/Test_diff_cuc_03.dump | 20 + src/testdir/dumps/Test_diff_cuc_04.dump | 20 + src/testdir/dumps/Test_diff_of_diff_01.dump | 20 + src/testdir/dumps/Test_diff_of_diff_02.dump | 20 + src/testdir/dumps/Test_diff_rnu_01.dump | 20 + src/testdir/dumps/Test_diff_rnu_02.dump | 20 + src/testdir/dumps/Test_diff_rnu_03.dump | 20 + src/testdir/dumps/Test_diff_scroll_1.dump | 12 + src/testdir/dumps/Test_diff_scroll_2.dump | 12 + src/testdir/dumps/Test_diff_scroll_change_01.dump | 20 + src/testdir/dumps/Test_diff_scroll_change_02.dump | 20 + src/testdir/dumps/Test_diff_scroll_change_03.dump | 20 + src/testdir/dumps/Test_diff_syntax_1.dump | 20 + src/testdir/dumps/Test_diff_with_cul_bri_01.dump | 20 + src/testdir/dumps/Test_diff_with_cul_bri_02.dump | 20 + src/testdir/dumps/Test_diff_with_cul_bri_03.dump | 20 + src/testdir/dumps/Test_diff_with_cul_bri_04.dump | 20 + .../dumps/Test_diff_with_cursorline_01.dump | 20 + .../dumps/Test_diff_with_cursorline_02.dump | 20 + .../dumps/Test_diff_with_cursorline_03.dump | 20 + .../dumps/Test_diff_with_cursorline_number_01.dump | 20 + .../dumps/Test_diff_with_cursorline_number_02.dump | 20 + src/testdir/dumps/Test_display_fillchars_1.dump | 12 + src/testdir/dumps/Test_display_fillchars_2.dump | 12 + src/testdir/dumps/Test_display_lastline_1.dump | 10 + src/testdir/dumps/Test_display_lastline_2.dump | 10 + src/testdir/dumps/Test_display_lastline_3.dump | 10 + src/testdir/dumps/Test_display_lastline_4.dump | 10 + src/testdir/dumps/Test_display_lastline_5.dump | 10 + src/testdir/dumps/Test_display_lastline_6.dump | 10 + .../dumps/Test_display_lastline_euro_1.dump | 10 + .../dumps/Test_display_lastline_euro_2.dump | 10 + .../dumps/Test_display_lastline_euro_3.dump | 10 + .../dumps/Test_display_lastline_euro_4.dump | 10 + .../dumps/Test_display_lastline_euro_5.dump | 10 + .../dumps/Test_display_lastline_euro_6.dump | 10 + .../dumps/Test_display_scroll_at_topline.dump | 4 + .../dumps/Test_display_scroll_update_visual.dump | 8 + src/testdir/dumps/Test_display_unprintable_01.dump | 9 + src/testdir/dumps/Test_display_unprintable_02.dump | 9 + .../dumps/Test_display_visual_block_scroll.dump | 7 + src/testdir/dumps/Test_echowin_eval.dump | 8 + src/testdir/dumps/Test_echowin_showmode.dump | 8 + src/testdir/dumps/Test_echowindow_1.dump | 8 + src/testdir/dumps/Test_echowindow_2.dump | 8 + src/testdir/dumps/Test_echowindow_3.dump | 8 + src/testdir/dumps/Test_echowindow_4.dump | 8 + src/testdir/dumps/Test_echowindow_5.dump | 8 + src/testdir/dumps/Test_echowindow_6.dump | 8 + src/testdir/dumps/Test_echowindow_7.dump | 8 + src/testdir/dumps/Test_echowindow_8.dump | 8 + src/testdir/dumps/Test_echowindow_9.dump | 8 + src/testdir/dumps/Test_fileinfo_after_echo.dump | 6 + src/testdir/dumps/Test_folds_with_rnu_01.dump | 20 + src/testdir/dumps/Test_folds_with_rnu_02.dump | 20 + src/testdir/dumps/Test_functions_echoraw.dump | 5 + src/testdir/dumps/Test_hlsearch_1.dump | 6 + src/testdir/dumps/Test_hlsearch_2.dump | 6 + .../dumps/Test_hlsearch_block_visual_match.dump | 9 + src/testdir/dumps/Test_hlsearch_ctrlr_1.dump | 6 + .../dumps/Test_hlsearch_cursearch_changed_1.dump | 9 + .../Test_hlsearch_cursearch_multiple_line_1.dump | 9 + .../Test_hlsearch_cursearch_multiple_line_2.dump | 9 + .../Test_hlsearch_cursearch_multiple_line_3.dump | 9 + .../Test_hlsearch_cursearch_multiple_line_4.dump | 9 + .../Test_hlsearch_cursearch_multiple_line_5.dump | 9 + .../Test_hlsearch_cursearch_single_line_1.dump | 9 + .../Test_hlsearch_cursearch_single_line_2.dump | 9 + .../Test_hlsearch_cursearch_single_line_2a.dump | 9 + .../Test_hlsearch_cursearch_single_line_2b.dump | 9 + .../Test_hlsearch_cursearch_single_line_3.dump | 9 + src/testdir/dumps/Test_hlsearch_visual_1.dump | 6 + src/testdir/dumps/Test_hor_scroll_1.dump | 8 + src/testdir/dumps/Test_hor_scroll_2.dump | 8 + src/testdir/dumps/Test_hor_scroll_3.dump | 8 + src/testdir/dumps/Test_hor_scroll_4.dump | 8 + src/testdir/dumps/Test_hor_scroll_5.dump | 8 + src/testdir/dumps/Test_incsearch_change_01.dump | 9 + src/testdir/dumps/Test_incsearch_newline1.dump | 5 + src/testdir/dumps/Test_incsearch_newline2.dump | 5 + src/testdir/dumps/Test_incsearch_newline3.dump | 5 + src/testdir/dumps/Test_incsearch_newline4.dump | 5 + src/testdir/dumps/Test_incsearch_newline5.dump | 5 + src/testdir/dumps/Test_incsearch_scrolling_01.dump | 9 + src/testdir/dumps/Test_incsearch_search_01.dump | 9 + src/testdir/dumps/Test_incsearch_search_02.dump | 9 + src/testdir/dumps/Test_incsearch_sort_01.dump | 9 + src/testdir/dumps/Test_incsearch_sort_02.dump | 9 + src/testdir/dumps/Test_incsearch_sub_01.dump | 9 + src/testdir/dumps/Test_incsearch_sub_02.dump | 9 + .../dumps/Test_incsearch_substitute_01.dump | 9 + .../dumps/Test_incsearch_substitute_02.dump | 9 + .../dumps/Test_incsearch_substitute_03.dump | 9 + .../dumps/Test_incsearch_substitute_04.dump | 9 + .../dumps/Test_incsearch_substitute_05.dump | 9 + .../dumps/Test_incsearch_substitute_06.dump | 9 + .../dumps/Test_incsearch_substitute_07.dump | 9 + .../dumps/Test_incsearch_substitute_08.dump | 9 + .../dumps/Test_incsearch_substitute_09.dump | 9 + .../dumps/Test_incsearch_substitute_10.dump | 9 + .../dumps/Test_incsearch_substitute_11.dump | 9 + .../dumps/Test_incsearch_substitute_12.dump | 9 + .../dumps/Test_incsearch_substitute_13.dump | 9 + .../dumps/Test_incsearch_substitute_14.dump | 9 + .../dumps/Test_incsearch_substitute_15.dump | 4 + src/testdir/dumps/Test_incsearch_vimgrep_01.dump | 9 + src/testdir/dumps/Test_incsearch_vimgrep_02.dump | 9 + src/testdir/dumps/Test_incsearch_vimgrep_03.dump | 9 + src/testdir/dumps/Test_incsearch_vimgrep_04.dump | 9 + src/testdir/dumps/Test_incsearch_vimgrep_05.dump | 9 + src/testdir/dumps/Test_job_buffer_scroll_1.dump | 10 + .../dumps/Test_keytyped_in_nested_func.dump | 6 + .../dumps/Test_linebreak_reset_restore_1.dump | 8 + src/testdir/dumps/Test_listchars_01.dump | 10 + src/testdir/dumps/Test_listchars_02.dump | 10 + src/testdir/dumps/Test_listchars_03.dump | 10 + src/testdir/dumps/Test_listchars_04.dump | 10 + src/testdir/dumps/Test_listchars_05.dump | 10 + src/testdir/dumps/Test_listchars_06.dump | 10 + src/testdir/dumps/Test_listchars_07.dump | 10 + src/testdir/dumps/Test_long_file_name_1.dump | 8 + .../dumps/Test_long_text_with_padding_1.dump | 8 + .../dumps/Test_long_text_with_padding_2.dump | 8 + src/testdir/dumps/Test_map_expr_1.dump | 10 + src/testdir/dumps/Test_map_expr_2.dump | 10 + src/testdir/dumps/Test_map_expr_3.dump | 10 + src/testdir/dumps/Test_map_expr_4.dump | 10 + src/testdir/dumps/Test_map_list_1.dump | 6 + src/testdir/dumps/Test_match_linebreak.dump | 10 + src/testdir/dumps/Test_match_tab_linebreak.dump | 10 + src/testdir/dumps/Test_match_with_incsearch_1.dump | 6 + src/testdir/dumps/Test_match_with_incsearch_2.dump | 6 + src/testdir/dumps/Test_matchadd_1.dump | 12 + src/testdir/dumps/Test_matchaddpos_1.dump | 14 + src/testdir/dumps/Test_matchclear_1.dump | 12 + src/testdir/dumps/Test_matchdelete_1.dump | 12 + .../dumps/Test_matchparen_clear_highlight_1.dump | 5 + .../dumps/Test_matchparen_clear_highlight_2.dump | 5 + src/testdir/dumps/Test_misplaced_type.dump | 6 + src/testdir/dumps/Test_mode_updated_1.dump | 5 + src/testdir/dumps/Test_more_scrollback_1.dump | 10 + src/testdir/dumps/Test_more_scrollback_2.dump | 10 + src/testdir/dumps/Test_move_undo_1.dump | 10 + src/testdir/dumps/Test_move_undo_2.dump | 10 + .../dumps/Test_popup_and_previewwindow_01.dump | 20 + src/testdir/dumps/Test_popup_command_01.dump | 20 + src/testdir/dumps/Test_popup_command_02.dump | 20 + src/testdir/dumps/Test_popup_command_03.dump | 20 + src/testdir/dumps/Test_popup_command_04.dump | 20 + src/testdir/dumps/Test_popup_command_05.dump | 20 + src/testdir/dumps/Test_popup_position_01.dump | 8 + src/testdir/dumps/Test_popup_position_02.dump | 8 + src/testdir/dumps/Test_popup_position_03.dump | 8 + src/testdir/dumps/Test_popup_position_04.dump | 10 + .../dumps/Test_popup_prop_not_visible_01.dump | 10 + .../dumps/Test_popup_prop_not_visible_01a.dump | 10 + .../dumps/Test_popup_prop_not_visible_01b.dump | 10 + .../dumps/Test_popup_prop_not_visible_02.dump | 10 + .../dumps/Test_popup_prop_not_visible_03.dump | 10 + src/testdir/dumps/Test_popup_settext_01.dump | 10 + src/testdir/dumps/Test_popup_settext_02.dump | 10 + src/testdir/dumps/Test_popup_settext_03.dump | 10 + src/testdir/dumps/Test_popup_settext_04.dump | 10 + src/testdir/dumps/Test_popup_settext_05.dump | 10 + src/testdir/dumps/Test_popup_settext_06.dump | 10 + src/testdir/dumps/Test_popup_settext_07.dump | 10 + src/testdir/dumps/Test_popup_textprop_01.dump | 10 + src/testdir/dumps/Test_popup_textprop_02.dump | 10 + src/testdir/dumps/Test_popup_textprop_03.dump | 10 + src/testdir/dumps/Test_popup_textprop_04.dump | 10 + src/testdir/dumps/Test_popup_textprop_05.dump | 10 + src/testdir/dumps/Test_popup_textprop_06.dump | 10 + src/testdir/dumps/Test_popup_textprop_07.dump | 10 + src/testdir/dumps/Test_popup_textprop_corn_1.dump | 12 + src/testdir/dumps/Test_popup_textprop_corn_2.dump | 12 + src/testdir/dumps/Test_popup_textprop_corn_3.dump | 12 + src/testdir/dumps/Test_popup_textprop_corn_4.dump | 12 + src/testdir/dumps/Test_popup_textprop_corn_5.dump | 12 + src/testdir/dumps/Test_popup_textprop_corn_6.dump | 12 + src/testdir/dumps/Test_popup_textprop_off_1.dump | 12 + src/testdir/dumps/Test_popup_textprop_off_2.dump | 12 + src/testdir/dumps/Test_popupwin_01.dump | 10 + src/testdir/dumps/Test_popupwin_02.dump | 10 + src/testdir/dumps/Test_popupwin_03.dump | 10 + src/testdir/dumps/Test_popupwin_04.dump | 10 + src/testdir/dumps/Test_popupwin_04a.dump | 10 + src/testdir/dumps/Test_popupwin_05.dump | 10 + src/testdir/dumps/Test_popupwin_06.dump | 10 + src/testdir/dumps/Test_popupwin_07.dump | 10 + src/testdir/dumps/Test_popupwin_08.dump | 10 + src/testdir/dumps/Test_popupwin_10.dump | 10 + src/testdir/dumps/Test_popupwin_11.dump | 10 + src/testdir/dumps/Test_popupwin_20.dump | 15 + src/testdir/dumps/Test_popupwin_21.dump | 15 + src/testdir/dumps/Test_popupwin_22.dump | 12 + src/testdir/dumps/Test_popupwin_23.dump | 12 + src/testdir/dumps/Test_popupwin_24.dump | 12 + src/testdir/dumps/Test_popupwin_atcursor_pos.dump | 12 + src/testdir/dumps/Test_popupwin_behind.dump | 10 + src/testdir/dumps/Test_popupwin_beval_1.dump | 10 + src/testdir/dumps/Test_popupwin_beval_2.dump | 10 + src/testdir/dumps/Test_popupwin_beval_3.dump | 10 + src/testdir/dumps/Test_popupwin_close_01.dump | 10 + src/testdir/dumps/Test_popupwin_close_02.dump | 10 + src/testdir/dumps/Test_popupwin_close_03.dump | 10 + src/testdir/dumps/Test_popupwin_close_04.dump | 10 + src/testdir/dumps/Test_popupwin_close_05.dump | 10 + src/testdir/dumps/Test_popupwin_corners.dump | 12 + src/testdir/dumps/Test_popupwin_ctrl_c.dump | 10 + src/testdir/dumps/Test_popupwin_cursorline_1.dump | 10 + src/testdir/dumps/Test_popupwin_cursorline_2.dump | 10 + src/testdir/dumps/Test_popupwin_cursorline_3.dump | 10 + src/testdir/dumps/Test_popupwin_cursorline_4.dump | 10 + src/testdir/dumps/Test_popupwin_cursorline_5.dump | 10 + src/testdir/dumps/Test_popupwin_cursorline_6.dump | 10 + src/testdir/dumps/Test_popupwin_cursorline_7.dump | 10 + src/testdir/dumps/Test_popupwin_cursorline_8.dump | 10 + src/testdir/dumps/Test_popupwin_doublewidth_1.dump | 10 + src/testdir/dumps/Test_popupwin_drag_01.dump | 10 + src/testdir/dumps/Test_popupwin_drag_02.dump | 10 + src/testdir/dumps/Test_popupwin_drag_03.dump | 10 + src/testdir/dumps/Test_popupwin_drag_04.dump | 10 + src/testdir/dumps/Test_popupwin_drag_05.dump | 10 + src/testdir/dumps/Test_popupwin_drag_06.dump | 10 + .../dumps/Test_popupwin_drag_minwidth_1.dump | 10 + .../dumps/Test_popupwin_drag_minwidth_2.dump | 10 + .../dumps/Test_popupwin_drag_minwidth_3.dump | 10 + src/testdir/dumps/Test_popupwin_firstline_1.dump | 10 + src/testdir/dumps/Test_popupwin_firstline_2.dump | 10 + src/testdir/dumps/Test_popupwin_infopopup_1.dump | 14 + src/testdir/dumps/Test_popupwin_infopopup_2.dump | 14 + src/testdir/dumps/Test_popupwin_infopopup_3.dump | 14 + src/testdir/dumps/Test_popupwin_infopopup_4.dump | 14 + src/testdir/dumps/Test_popupwin_infopopup_5.dump | 14 + src/testdir/dumps/Test_popupwin_infopopup_6.dump | 14 + src/testdir/dumps/Test_popupwin_infopopup_7.dump | 14 + src/testdir/dumps/Test_popupwin_infopopup_8.dump | 14 + src/testdir/dumps/Test_popupwin_infopopup_9.dump | 14 + .../dumps/Test_popupwin_infopopup_align_1.dump | 14 + .../dumps/Test_popupwin_infopopup_align_2.dump | 14 + .../dumps/Test_popupwin_infopopup_align_3.dump | 14 + .../dumps/Test_popupwin_infopopup_hidden_1.dump | 14 + .../dumps/Test_popupwin_infopopup_hidden_2.dump | 14 + .../dumps/Test_popupwin_infopopup_hidden_3.dump | 14 + .../dumps/Test_popupwin_infopopup_nb_1.dump | 14 + .../dumps/Test_popupwin_infopopup_wide_1.dump | 8 + src/testdir/dumps/Test_popupwin_longtitle_1.dump | 10 + src/testdir/dumps/Test_popupwin_longtitle_2.dump | 10 + src/testdir/dumps/Test_popupwin_longtitle_3.dump | 10 + src/testdir/dumps/Test_popupwin_longtitle_4.dump | 10 + src/testdir/dumps/Test_popupwin_mask_1.dump | 13 + src/testdir/dumps/Test_popupwin_mask_2.dump | 13 + src/testdir/dumps/Test_popupwin_mask_3.dump | 13 + src/testdir/dumps/Test_popupwin_mask_4.dump | 13 + src/testdir/dumps/Test_popupwin_mask_5.dump | 13 + src/testdir/dumps/Test_popupwin_matches.dump | 10 + src/testdir/dumps/Test_popupwin_menu_01.dump | 10 + src/testdir/dumps/Test_popupwin_menu_02.dump | 10 + src/testdir/dumps/Test_popupwin_menu_03.dump | 10 + src/testdir/dumps/Test_popupwin_menu_04.dump | 10 + src/testdir/dumps/Test_popupwin_menu_filter_1.dump | 10 + src/testdir/dumps/Test_popupwin_menu_filter_2.dump | 10 + src/testdir/dumps/Test_popupwin_menu_filter_3.dump | 10 + src/testdir/dumps/Test_popupwin_menu_filter_4.dump | 10 + src/testdir/dumps/Test_popupwin_menu_filter_5.dump | 10 + .../dumps/Test_popupwin_menu_maxwidth_1.dump | 13 + src/testdir/dumps/Test_popupwin_menu_scroll_1.dump | 10 + src/testdir/dumps/Test_popupwin_menu_scroll_2.dump | 10 + src/testdir/dumps/Test_popupwin_menu_scroll_3.dump | 10 + src/testdir/dumps/Test_popupwin_menu_scroll_4.dump | 10 + src/testdir/dumps/Test_popupwin_menu_scroll_5.dump | 10 + src/testdir/dumps/Test_popupwin_menu_scroll_6.dump | 10 + .../dumps/Test_popupwin_multibytetitle.dump | 10 + src/testdir/dumps/Test_popupwin_normal_cmd.dump | 10 + src/testdir/dumps/Test_popupwin_nospace.dump | 12 + src/testdir/dumps/Test_popupwin_notify_01.dump | 10 + src/testdir/dumps/Test_popupwin_notify_02.dump | 10 + src/testdir/dumps/Test_popupwin_nowrap.dump | 10 + .../dumps/Test_popupwin_poptermscroll_1.dump | 15 + .../dumps/Test_popupwin_poptermscroll_2.dump | 15 + .../dumps/Test_popupwin_poptermscroll_3.dump | 15 + .../dumps/Test_popupwin_poptermscroll_4.dump | 15 + .../dumps/Test_popupwin_popupmenu_masking_1.dump | 14 + .../dumps/Test_popupwin_popupmenu_masking_2.dump | 14 + .../dumps/Test_popupwin_previewpopup_1.dump | 14 + .../dumps/Test_popupwin_previewpopup_10.dump | 14 + .../dumps/Test_popupwin_previewpopup_2.dump | 14 + .../dumps/Test_popupwin_previewpopup_3.dump | 14 + .../dumps/Test_popupwin_previewpopup_4.dump | 14 + .../dumps/Test_popupwin_previewpopup_5.dump | 14 + .../dumps/Test_popupwin_previewpopup_6.dump | 14 + .../dumps/Test_popupwin_previewpopup_7.dump | 14 + .../dumps/Test_popupwin_previewpopup_8.dump | 14 + .../dumps/Test_popupwin_previewpopup_9.dump | 14 + src/testdir/dumps/Test_popupwin_scroll_1.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_10.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_11.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_12.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_13.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_2.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_3.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_4.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_5.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_6.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_7.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_8.dump | 10 + src/testdir/dumps/Test_popupwin_scroll_9.dump | 10 + src/testdir/dumps/Test_popupwin_select_01.dump | 10 + src/testdir/dumps/Test_popupwin_select_02.dump | 10 + .../dumps/Test_popupwin_set_firstline_1.dump | 16 + .../dumps/Test_popupwin_set_firstline_2.dump | 16 + src/testdir/dumps/Test_popupwin_showbreak.dump | 10 + src/testdir/dumps/Test_popupwin_sign_1.dump | 10 + src/testdir/dumps/Test_popupwin_sign_2.dump | 10 + src/testdir/dumps/Test_popupwin_term_01.dump | 16 + src/testdir/dumps/Test_popupwin_term_02.dump | 16 + src/testdir/dumps/Test_popupwin_term_03.dump | 16 + src/testdir/dumps/Test_popupwin_term_04.dump | 16 + .../dumps/Test_popupwin_three_errors_1.dump | 10 + .../dumps/Test_popupwin_three_errors_2.dump | 10 + src/testdir/dumps/Test_popupwin_title.dump | 10 + src/testdir/dumps/Test_popupwin_toohigh_1.dump | 10 + src/testdir/dumps/Test_popupwin_toohigh_2.dump | 10 + src/testdir/dumps/Test_popupwin_toohigh_3.dump | 10 + src/testdir/dumps/Test_popupwin_win_execute.dump | 10 + .../Test_popupwin_win_execute_cursorline.dump | 14 + src/testdir/dumps/Test_popupwin_wrap.dump | 10 + src/testdir/dumps/Test_popupwin_wrap_1.dump | 10 + src/testdir/dumps/Test_popupwin_wrap_2.dump | 10 + src/testdir/dumps/Test_popupwin_wrong_name.dump | 10 + .../dumps/Test_prop_above_below_empty_1.dump | 16 + .../dumps/Test_prop_above_below_empty_2.dump | 16 + .../dumps/Test_prop_above_below_empty_3.dump | 16 + .../dumps/Test_prop_above_below_empty_4.dump | 16 + .../dumps/Test_prop_above_below_empty_5.dump | 16 + .../Test_prop_above_below_smoothscroll_1.dump | 8 + .../Test_prop_above_below_smoothscroll_10.dump | 8 + .../Test_prop_above_below_smoothscroll_11.dump | 8 + .../Test_prop_above_below_smoothscroll_12.dump | 8 + .../Test_prop_above_below_smoothscroll_13.dump | 8 + .../Test_prop_above_below_smoothscroll_14.dump | 8 + .../Test_prop_above_below_smoothscroll_15.dump | 8 + .../Test_prop_above_below_smoothscroll_16.dump | 8 + .../Test_prop_above_below_smoothscroll_2.dump | 8 + .../Test_prop_above_below_smoothscroll_3.dump | 8 + .../Test_prop_above_below_smoothscroll_4.dump | 8 + .../Test_prop_above_below_smoothscroll_5.dump | 8 + .../Test_prop_above_below_smoothscroll_6.dump | 8 + .../Test_prop_above_below_smoothscroll_7.dump | 8 + .../Test_prop_above_below_smoothscroll_8.dump | 8 + .../Test_prop_above_below_smoothscroll_9.dump | 8 + src/testdir/dumps/Test_prop_above_empty_1.dump | 16 + src/testdir/dumps/Test_prop_above_empty_2.dump | 16 + src/testdir/dumps/Test_prop_above_number_1.dump | 8 + src/testdir/dumps/Test_prop_above_number_2.dump | 8 + src/testdir/dumps/Test_prop_after_linebreak.dump | 10 + src/testdir/dumps/Test_prop_after_tab.dump | 10 + src/testdir/dumps/Test_prop_at_same_pos.dump | 5 + src/testdir/dumps/Test_prop_before_tab_01.dump | 8 + src/testdir/dumps/Test_prop_before_tab_02.dump | 8 + src/testdir/dumps/Test_prop_before_tab_03.dump | 8 + src/testdir/dumps/Test_prop_before_tab_04.dump | 8 + src/testdir/dumps/Test_prop_before_tab_05.dump | 8 + src/testdir/dumps/Test_prop_before_tab_06.dump | 8 + src/testdir/dumps/Test_prop_before_tab_07.dump | 8 + src/testdir/dumps/Test_prop_before_tab_08.dump | 8 + src/testdir/dumps/Test_prop_before_tab_09.dump | 8 + src/testdir/dumps/Test_prop_before_tab_10.dump | 8 + .../dumps/Test_prop_below_after_empty_1.dump | 8 + .../dumps/Test_prop_below_after_empty_2.dump | 8 + .../dumps/Test_prop_below_after_empty_3.dump | 8 + .../dumps/Test_prop_below_split_line_1.dump | 8 + .../dumps/Test_prop_below_split_line_2.dump | 8 + .../dumps/Test_prop_below_split_line_3.dump | 8 + src/testdir/dumps/Test_prop_delete_updates_1.dump | 10 + src/testdir/dumps/Test_prop_delete_updates_2.dump | 10 + src/testdir/dumps/Test_prop_delete_updates_3.dump | 10 + src/testdir/dumps/Test_prop_diff_mode_1.dump | 10 + src/testdir/dumps/Test_prop_diff_mode_2.dump | 10 + .../dumps/Test_prop_insert_list_mode_1.dump | 8 + .../dumps/Test_prop_insert_list_mode_2.dump | 8 + .../dumps/Test_prop_insert_list_mode_3.dump | 8 + .../dumps/Test_prop_insert_start_incl_1.dump | 8 + .../dumps/Test_prop_insert_start_incl_2.dump | 8 + .../dumps/Test_prop_insert_start_incl_3.dump | 8 + .../dumps/Test_prop_insert_start_incl_4.dump | 8 + .../dumps/Test_prop_insert_start_incl_5.dump | 8 + .../dumps/Test_prop_insert_start_incl_6.dump | 8 + .../dumps/Test_prop_insert_start_incl_7.dump | 8 + .../dumps/Test_prop_insert_start_incl_8.dump | 8 + src/testdir/dumps/Test_prop_inserts_text_1.dump | 8 + src/testdir/dumps/Test_prop_inserts_text_2.dump | 8 + src/testdir/dumps/Test_prop_inserts_text_3.dump | 8 + src/testdir/dumps/Test_prop_inserts_text_4.dump | 8 + src/testdir/dumps/Test_prop_inserts_text_5.dump | 8 + src/testdir/dumps/Test_prop_inserts_text_6.dump | 8 + src/testdir/dumps/Test_prop_inserts_text_hi_1.dump | 6 + src/testdir/dumps/Test_prop_inserts_text_hi_2.dump | 6 + src/testdir/dumps/Test_prop_inserts_text_hi_3.dump | 6 + src/testdir/dumps/Test_prop_inserts_text_hi_4.dump | 6 + src/testdir/dumps/Test_prop_inserts_text_hi_5.dump | 6 + src/testdir/dumps/Test_prop_inserts_text_hi_6.dump | 6 + src/testdir/dumps/Test_prop_linebreak_1.dump | 10 + src/testdir/dumps/Test_prop_linebreak_2.dump | 10 + src/testdir/dumps/Test_prop_multibyte_below_1.dump | 10 + src/testdir/dumps/Test_prop_negative_error_1.dump | 8 + src/testdir/dumps/Test_prop_negative_error_2.dump | 8 + .../dumps/Test_prop_right_align_twice_1.dump | 8 + .../dumps/Test_prop_right_align_twice_2.dump | 8 + .../dumps/Test_prop_right_align_twice_3.dump | 8 + src/testdir/dumps/Test_prop_text_change_arg_1.dump | 5 + src/testdir/dumps/Test_prop_text_change_arg_2.dump | 5 + .../dumps/Test_prop_text_with_padding_1.dump | 8 + .../dumps/Test_prop_text_with_padding_2.dump | 8 + .../dumps/Test_prop_text_with_padding_3.dump | 8 + .../dumps/Test_prop_text_with_padding_4.dump | 8 + src/testdir/dumps/Test_prop_with_linebreak_1.dump | 6 + src/testdir/dumps/Test_prop_with_linebreak_2.dump | 6 + src/testdir/dumps/Test_prop_with_text_above_1.dump | 9 + .../dumps/Test_prop_with_text_above_1a.dump | 9 + .../dumps/Test_prop_with_text_above_1b.dump | 9 + .../dumps/Test_prop_with_text_above_1c.dump | 9 + src/testdir/dumps/Test_prop_with_text_above_2.dump | 9 + src/testdir/dumps/Test_prop_with_text_above_3.dump | 9 + src/testdir/dumps/Test_prop_with_text_above_4.dump | 9 + src/testdir/dumps/Test_prop_with_text_above_5.dump | 9 + src/testdir/dumps/Test_prop_with_text_above_6.dump | 9 + src/testdir/dumps/Test_prop_with_text_above_7.dump | 9 + src/testdir/dumps/Test_prop_with_text_above_8.dump | 9 + src/testdir/dumps/Test_prop_with_text_above_9.dump | 9 + src/testdir/dumps/Test_prop_with_text_after_1.dump | 8 + .../Test_prop_with_text_after_below_trunc_1.dump | 8 + .../Test_prop_with_text_after_below_trunc_2.dump | 8 + .../Test_prop_with_text_after_below_trunc_3.dump | 8 + .../Test_prop_with_text_after_join_split_1.dump | 8 + .../Test_prop_with_text_after_join_split_2.dump | 8 + .../Test_prop_with_text_after_join_split_3.dump | 8 + .../Test_prop_with_text_after_join_split_4.dump | 8 + .../Test_prop_with_text_after_join_split_5.dump | 8 + .../dumps/Test_prop_with_text_after_joined_1.dump | 6 + .../dumps/Test_prop_with_text_after_nowrap_1.dump | 12 + .../dumps/Test_prop_with_text_after_nowrap_2.dump | 12 + .../dumps/Test_prop_with_text_after_nowrap_3.dump | 12 + .../dumps/Test_prop_with_text_after_trunc_1.dump | 9 + .../dumps/Test_prop_with_text_after_trunc_2.dump | 9 + .../dumps/Test_prop_with_text_after_trunc_3.dump | 9 + .../dumps/Test_prop_with_text_after_trunc_4.dump | 9 + .../dumps/Test_prop_with_text_after_trunc_5.dump | 9 + .../dumps/Test_prop_with_text_after_wraps_1.dump | 9 + .../Test_prop_with_text_below_after_match_1.dump | 8 + .../dumps/Test_prop_with_text_below_cul_1.dump | 6 + .../dumps/Test_prop_with_text_below_nowrap_1.dump | 8 + .../dumps/Test_prop_with_text_below_nowrap_2.dump | 8 + .../dumps/Test_prop_with_text_cursormoved_1.dump | 8 + .../dumps/Test_prop_with_text_cursormoved_2.dump | 8 + .../dumps/Test_prop_with_text_empty_line_1.dump | 8 + .../dumps/Test_prop_with_text_empty_line_2.dump | 8 + .../dumps/Test_prop_with_text_empty_line_3.dump | 8 + .../dumps/Test_prop_with_text_empty_line_4.dump | 8 + .../dumps/Test_prop_with_text_empty_line_5.dump | 8 + .../dumps/Test_prop_with_text_override_1.dump | 6 + .../dumps/Test_prop_with_text_override_2.dump | 6 + src/testdir/dumps/Test_prop_with_wrap_1.dump | 6 + src/testdir/dumps/Test_props_after_1.dump | 8 + src/testdir/dumps/Test_props_after_2.dump | 8 + src/testdir/dumps/Test_pum_preview_1.dump | 12 + src/testdir/dumps/Test_pum_preview_2.dump | 12 + src/testdir/dumps/Test_pum_preview_3.dump | 12 + src/testdir/dumps/Test_pum_preview_4.dump | 12 + src/testdir/dumps/Test_pum_rightleft_01.dump | 8 + src/testdir/dumps/Test_pum_rightleft_02.dump | 7 + src/testdir/dumps/Test_pum_scrollbar_01.dump | 7 + src/testdir/dumps/Test_pum_scrollbar_02.dump | 7 + src/testdir/dumps/Test_pum_stopped_by_timer.dump | 12 + .../dumps/Test_pum_with_folds_two_tabs.dump | 10 + src/testdir/dumps/Test_pum_with_preview_win.dump | 12 + src/testdir/dumps/Test_quickfix_cwindow_1.dump | 12 + src/testdir/dumps/Test_quickfix_cwindow_2.dump | 12 + src/testdir/dumps/Test_quickfix_cwindow_3.dump | 12 + src/testdir/dumps/Test_quickfix_cwindow_4.dump | 12 + src/testdir/dumps/Test_quickfix_window_fails.dump | 13 + src/testdir/dumps/Test_quit_long_message.dump | 10 + src/testdir/dumps/Test_redraw_in_autocmd_1.dump | 8 + src/testdir/dumps/Test_redraw_in_autocmd_2.dump | 8 + .../dumps/Test_redrawstatus_in_autocmd_1.dump | 8 + .../dumps/Test_redrawstatus_in_autocmd_2.dump | 8 + .../dumps/Test_redrawstatus_in_autocmd_3.dump | 8 + .../dumps/Test_redrawstatus_in_autocmd_4.dump | 8 + .../dumps/Test_redrawstatus_in_autocmd_5.dump | 8 + .../dumps/Test_relativenumber_callback_1.dump | 8 + src/testdir/dumps/Test_relnr_colors_1.dump | 10 + src/testdir/dumps/Test_relnr_colors_2.dump | 10 + src/testdir/dumps/Test_relnr_colors_3.dump | 10 + src/testdir/dumps/Test_relnr_colors_4.dump | 10 + src/testdir/dumps/Test_scroll_no_region_1.dump | 10 + src/testdir/dumps/Test_scroll_no_region_2.dump | 10 + src/testdir/dumps/Test_scroll_no_region_3.dump | 10 + src/testdir/dumps/Test_scroll_no_region_4.dump | 10 + src/testdir/dumps/Test_scroll_no_region_5.dump | 10 + src/testdir/dumps/Test_scroll_no_region_6.dump | 10 + src/testdir/dumps/Test_scrollbar_on_wide_char.dump | 10 + src/testdir/dumps/Test_searchstat_1.dump | 10 + src/testdir/dumps/Test_searchstat_2.dump | 10 + src/testdir/dumps/Test_searchstat_3.dump | 10 + src/testdir/dumps/Test_searchstat_4.dump | 10 + src/testdir/dumps/Test_searchstat_inc_1.dump | 10 + src/testdir/dumps/Test_searchstat_inc_2.dump | 10 + src/testdir/dumps/Test_searchstat_inc_3.dump | 10 + src/testdir/dumps/Test_searchstatgd_1.dump | 10 + src/testdir/dumps/Test_searchstatgd_2.dump | 10 + src/testdir/dumps/Test_setcellwidths_dump_1.dump | 6 + src/testdir/dumps/Test_setcellwidths_dump_2.dump | 6 + src/testdir/dumps/Test_sign_cursor_1.dump | 6 + src/testdir/dumps/Test_sign_cursor_2.dump | 6 + src/testdir/dumps/Test_sign_cursor_3.dump | 6 + src/testdir/dumps/Test_sign_cursor_4.dump | 6 + src/testdir/dumps/Test_sign_cursor_5.dump | 6 + src/testdir/dumps/Test_sign_cursor_6.dump | 6 + src/testdir/dumps/Test_smooth_diff_1.dump | 8 + src/testdir/dumps/Test_smooth_list_1.dump | 8 + src/testdir/dumps/Test_smooth_list_2.dump | 8 + src/testdir/dumps/Test_smooth_long_1.dump | 6 + src/testdir/dumps/Test_smooth_long_10.dump | 6 + src/testdir/dumps/Test_smooth_long_11.dump | 6 + src/testdir/dumps/Test_smooth_long_12.dump | 6 + src/testdir/dumps/Test_smooth_long_13.dump | 6 + src/testdir/dumps/Test_smooth_long_14.dump | 6 + src/testdir/dumps/Test_smooth_long_15.dump | 6 + src/testdir/dumps/Test_smooth_long_2.dump | 6 + src/testdir/dumps/Test_smooth_long_3.dump | 6 + src/testdir/dumps/Test_smooth_long_4.dump | 6 + src/testdir/dumps/Test_smooth_long_5.dump | 6 + src/testdir/dumps/Test_smooth_long_6.dump | 6 + src/testdir/dumps/Test_smooth_long_7.dump | 6 + src/testdir/dumps/Test_smooth_long_8.dump | 6 + src/testdir/dumps/Test_smooth_long_9.dump | 6 + .../dumps/Test_smooth_long_showbreak_1.dump | 6 + .../dumps/Test_smooth_long_showbreak_2.dump | 6 + src/testdir/dumps/Test_smooth_number_1.dump | 12 + src/testdir/dumps/Test_smooth_number_2.dump | 12 + src/testdir/dumps/Test_smooth_number_3.dump | 12 + src/testdir/dumps/Test_smooth_number_4.dump | 12 + src/testdir/dumps/Test_smooth_number_5.dump | 12 + src/testdir/dumps/Test_smooth_number_6.dump | 12 + src/testdir/dumps/Test_smooth_number_7.dump | 12 + src/testdir/dumps/Test_smooth_one_long_1.dump | 6 + src/testdir/dumps/Test_smooth_one_long_2.dump | 6 + src/testdir/dumps/Test_smooth_wrap_1.dump | 8 + src/testdir/dumps/Test_smooth_wrap_2.dump | 8 + src/testdir/dumps/Test_smooth_wrap_3.dump | 8 + src/testdir/dumps/Test_smooth_wrap_4.dump | 8 + src/testdir/dumps/Test_smooth_wrap_5.dump | 8 + src/testdir/dumps/Test_smooth_wrap_6.dump | 8 + src/testdir/dumps/Test_smoothscroll_1.dump | 12 + src/testdir/dumps/Test_smoothscroll_2.dump | 12 + src/testdir/dumps/Test_smoothscroll_3.dump | 12 + src/testdir/dumps/Test_smoothscroll_4.dump | 12 + src/testdir/dumps/Test_smoothscroll_5.dump | 12 + src/testdir/dumps/Test_smoothscroll_6.dump | 12 + src/testdir/dumps/Test_smoothscroll_7.dump | 12 + src/testdir/dumps/Test_smoothscroll_8.dump | 12 + src/testdir/dumps/Test_smoothscroll_zero_1.dump | 6 + src/testdir/dumps/Test_smoothscroll_zero_2.dump | 6 + src/testdir/dumps/Test_spell_1.dump | 8 + src/testdir/dumps/Test_spell_2.dump | 8 + src/testdir/dumps/Test_spell_3.dump | 8 + src/testdir/dumps/Test_spell_4.dump | 8 + src/testdir/dumps/Test_spell_5.dump | 8 + src/testdir/dumps/Test_spell_compatible_1.dump | 8 + src/testdir/dumps/Test_spell_compatible_2.dump | 8 + src/testdir/dumps/Test_splitkeep_callback_1.dump | 8 + src/testdir/dumps/Test_splitkeep_callback_2.dump | 8 + src/testdir/dumps/Test_splitkeep_callback_3.dump | 8 + src/testdir/dumps/Test_splitkeep_callback_4.dump | 8 + src/testdir/dumps/Test_splitkeep_fold_1.dump | 10 + src/testdir/dumps/Test_splitkeep_fold_2.dump | 10 + src/testdir/dumps/Test_splitkeep_fold_3.dump | 10 + src/testdir/dumps/Test_splitkeep_fold_4.dump | 10 + src/testdir/dumps/Test_splitkeep_status_1.dump | 10 + src/testdir/dumps/Test_start_with_tabs.dump | 20 + src/testdir/dumps/Test_statusline_1.dump | 10 + src/testdir/dumps/Test_statusline_hl.dump | 6 + src/testdir/dumps/Test_statusline_mode_1.dump | 7 + src/testdir/dumps/Test_statusline_mode_2.dump | 7 + src/testdir/dumps/Test_statusline_showcmd_1.dump | 6 + src/testdir/dumps/Test_statusline_showcmd_2.dump | 6 + src/testdir/dumps/Test_statusline_showcmd_3.dump | 6 + src/testdir/dumps/Test_statusline_showcmd_4.dump | 6 + src/testdir/dumps/Test_statusline_showcmd_5.dump | 6 + .../dumps/Test_sub_highlight_zer_match_1.dump | 8 + src/testdir/dumps/Test_syntax_c_01.dump | 20 + src/testdir/dumps/Test_tabline_showcmd_1.dump | 6 + src/testdir/dumps/Test_tabline_showcmd_2.dump | 6 + src/testdir/dumps/Test_tabline_showcmd_3.dump | 6 + src/testdir/dumps/Test_tabline_showcmd_4.dump | 6 + src/testdir/dumps/Test_tabline_showcmd_5.dump | 6 + src/testdir/dumps/Test_tabpage_cmdheight.dump | 20 + src/testdir/dumps/Test_tenc_euc_jp_01.dump | 10 + src/testdir/dumps/Test_term_popup_bufline.dump | 15 + .../dumps/Test_terminal_all_ansi_colors.dump | 10 + .../dumps/Test_terminal_color_MyTermCol.dump | 15 + ...est_terminal_color_MyTermCol_over_Terminal.dump | 15 + .../dumps/Test_terminal_color_MyWinCol.dump | 15 + .../Test_terminal_color_MyWinCol_over_group.dump | 15 + .../dumps/Test_terminal_color_Terminal.dump | 15 + .../dumps/Test_terminal_color_gui_MyTermCol.dump | 15 + .../dumps/Test_terminal_color_gui_MyWinCol.dump | 15 + .../dumps/Test_terminal_color_gui_Terminal.dump | 15 + .../Test_terminal_color_gui_transp_MyTermCol.dump | 15 + .../Test_terminal_color_gui_transp_MyWinCol.dump | 15 + .../Test_terminal_color_gui_transp_Terminal.dump | 15 + .../Test_terminal_color_transp_MyTermCol.dump | 15 + .../dumps/Test_terminal_color_transp_MyWinCol.dump | 15 + .../dumps/Test_terminal_color_transp_Terminal.dump | 15 + src/testdir/dumps/Test_terminal_combining.dump | 9 + src/testdir/dumps/Test_terminal_dumpload.dump | 15 + src/testdir/dumps/Test_terminal_focus_1.dump | 6 + src/testdir/dumps/Test_terminal_focus_2.dump | 6 + src/testdir/dumps/Test_terminal_focus_3.dump | 6 + src/testdir/dumps/Test_terminal_from_cmd.dump | 20 + src/testdir/dumps/Test_terminal_normal_1.dump | 8 + src/testdir/dumps/Test_terminal_normal_2.dump | 8 + src/testdir/dumps/Test_terminal_normal_3.dump | 8 + src/testdir/dumps/Test_terminal_popup_1.dump | 15 + src/testdir/dumps/Test_terminal_popup_2.dump | 15 + src/testdir/dumps/Test_terminal_popup_3.dump | 15 + src/testdir/dumps/Test_terminal_popup_4.dump | 15 + src/testdir/dumps/Test_terminal_popup_5.dump | 15 + src/testdir/dumps/Test_terminal_popup_6.dump | 15 + src/testdir/dumps/Test_terminal_popup_7.dump | 15 + src/testdir/dumps/Test_terminal_popup_8.dump | 15 + .../dumps/Test_terminal_popup_MyPopupHlCol.dump | 15 + .../dumps/Test_terminal_popup_MyTermCol.dump | 15 + ...est_terminal_popup_MyTermCol_over_Terminal.dump | 15 + .../dumps/Test_terminal_popup_MyWinCol.dump | 15 + .../Test_terminal_popup_MyWinCol_over_group.dump | 15 + .../dumps/Test_terminal_popup_Terminal.dump | 15 + .../Test_terminal_popup_gui_MyPopupHlCol.dump | 15 + .../dumps/Test_terminal_popup_gui_MyTermCol.dump | 15 + .../dumps/Test_terminal_popup_gui_MyWinCol.dump | 15 + .../dumps/Test_terminal_popup_gui_Terminal.dump | 15 + ...est_terminal_popup_gui_transp_MyPopupHlCol.dump | 15 + .../Test_terminal_popup_gui_transp_MyTermCol.dump | 15 + .../Test_terminal_popup_gui_transp_MyWinCol.dump | 15 + .../Test_terminal_popup_gui_transp_Terminal.dump | 15 + src/testdir/dumps/Test_terminal_popup_m1.dump | 15 + .../Test_terminal_popup_transp_MyPopupHlCol.dump | 15 + .../Test_terminal_popup_transp_MyTermCol.dump | 15 + .../dumps/Test_terminal_popup_transp_MyWinCol.dump | 15 + .../dumps/Test_terminal_popup_transp_Terminal.dump | 15 + src/testdir/dumps/Test_terminal_scrollback_1.dump | 20 + src/testdir/dumps/Test_terminal_scrollback_2.dump | 20 + src/testdir/dumps/Test_terminal_scrollback_3.dump | 20 + .../Test_terminal_wincolor_split_MyWinCol.dump | 15 + .../Test_terminal_wincolor_split_MyWinCol2.dump | 15 + src/testdir/dumps/Test_text_after_nowrap_1.dump | 8 + src/testdir/dumps/Test_text_after_nowrap_2.dump | 8 + src/testdir/dumps/Test_text_after_nowrap_3.dump | 8 + src/testdir/dumps/Test_text_after_nowrap_4.dump | 8 + src/testdir/dumps/Test_text_after_nowrap_5.dump | 8 + .../dumps/Test_text_after_nowrap_list_1.dump | 6 + src/testdir/dumps/Test_text_below_nowrap_1.dump | 8 + src/testdir/dumps/Test_textprop_01.dump | 8 + src/testdir/dumps/Test_textprop_hl_override_1.dump | 8 + src/testdir/dumps/Test_textprop_hl_override_2.dump | 8 + src/testdir/dumps/Test_textprop_nesting.dump | 8 + src/testdir/dumps/Test_textprop_nowrap_01.dump | 6 + src/testdir/dumps/Test_textprop_nowrap_02.dump | 6 + src/testdir/dumps/Test_textprop_syn_1.dump | 6 + src/testdir/dumps/Test_textprop_tab.dump | 6 + src/testdir/dumps/Test_textprop_vis_01.dump | 12 + src/testdir/dumps/Test_textprop_vis_02.dump | 12 + src/testdir/dumps/Test_tselect_1.dump | 10 + src/testdir/dumps/Test_undo_after_write_1.dump | 6 + src/testdir/dumps/Test_undo_after_write_2.dump | 6 + src/testdir/dumps/Test_undo_after_write_2.vim | 2 + src/testdir/dumps/Test_verbose_option_1.dump | 12 + src/testdir/dumps/Test_verbose_system_1.dump | 10 + src/testdir/dumps/Test_verbose_system_1.vim | 5 + src/testdir/dumps/Test_verbose_system_2.dump | 10 + src/testdir/dumps/Test_verbose_system_2.vim | 5 + src/testdir/dumps/Test_vim9_closure_fails.dump | 6 + src/testdir/dumps/Test_vim9_no_redraw.dump | 6 + .../dumps/Test_vim9_reject_declaration_1.dump | 6 + .../dumps/Test_vim9_reject_declaration_2.dump | 6 + src/testdir/dumps/Test_vim9_silent_echo.dump | 6 + .../Test_virtual_text_in_popup_highlight_1.dump | 8 + .../dumps/Test_visual_block_with_virtualedit.dump | 8 + .../dumps/Test_visual_block_with_virtualedit2.dump | 8 + src/testdir/dumps/Test_wildmenu_1.dump | 8 + src/testdir/dumps/Test_wildmenu_2.dump | 8 + src/testdir/dumps/Test_wildmenu_3.dump | 8 + src/testdir/dumps/Test_wildmenu_4.dump | 8 + src/testdir/dumps/Test_wildmenu_pum_01.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_02.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_03.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_04.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_05.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_06.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_07.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_08.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_09.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_10.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_11.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_12.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_13.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_14.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_15.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_16.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_17.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_18.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_19.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_20.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_21.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_22.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_23.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_24.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_25.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_26.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_27.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_28.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_29.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_30.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_31.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_32.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_33.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_34.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_35.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_36.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_37.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_38.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_39.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_40.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_41.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_42.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_43.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_44.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_45.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_46.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_47.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_48.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_49.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_50.dump | 10 + .../dumps/Test_wildmenu_pum_clear_entries_1.dump | 10 + src/testdir/dumps/Test_wildmenu_pum_term_01.dump | 10 + .../dumps/Test_wildmenu_with_pum_foldexpr_1.dump | 10 + .../dumps/Test_wildmenu_with_pum_foldexpr_2.dump | 10 + src/testdir/dumps/Test_win_gotoid_1.dump | 15 + src/testdir/dumps/Test_win_gotoid_2.dump | 15 + src/testdir/dumps/Test_win_gotoid_3.dump | 15 + src/testdir/dumps/Test_winbar_not_visible.dump | 10 + .../Test_winbar_not_visible_custom_statusline.dump | 10 + src/testdir/dumps/Test_wincolor_01.dump | 8 + src/testdir/dumps/Test_wincolor_lcs.dump | 8 + src/testdir/dumps/Test_winline_rnu.dump | 5 + .../dumps/Test_winscrolled_not_when_defined_1.dump | 10 + .../dumps/Test_winscrolled_not_when_defined_2.dump | 10 + .../dumps/Test_winscrolled_once_only_1.dump | 10 + src/testdir/gen_opt_test.vim | 241 + src/testdir/gui_init.vim | 6 + src/testdir/gui_preinit.vim | 7 + src/testdir/keycode_check.json | 1 + src/testdir/keycode_check.vim | 470 + src/testdir/lsan-suppress.txt | 13 + src/testdir/mouse.vim | 372 + src/testdir/popupbounce.vim | 80 + src/testdir/python2/module.py | 2 + src/testdir/python3/module.py | 2 + src/testdir/python_after/after.py | 2 + src/testdir/python_before/before.py | 1 + src/testdir/python_before/before_1.py | 1 + src/testdir/python_before/before_2.py | 1 + src/testdir/pythonx/failing.py | 1 + src/testdir/pythonx/failing_import.py | 1 + src/testdir/pythonx/module.py | 1 + src/testdir/pythonx/modulex.py | 1 + src/testdir/pythonx/topmodule/__init__.py | 1 + .../pythonx/topmodule/submodule/__init__.py | 1 + .../topmodule/submodule/subsubmodule/__init__.py | 1 + .../submodule/subsubmodule/subsubsubmodule.py | 1 + src/testdir/pyxfile/py2_magic.py | 4 + src/testdir/pyxfile/py2_shebang.py | 4 + src/testdir/pyxfile/py3_magic.py | 4 + src/testdir/pyxfile/py3_shebang.py | 4 + src/testdir/pyxfile/pyx.py | 2 + src/testdir/runtest.vim | 618 + src/testdir/samples/crypt_sodium_invalid.txt | Bin 0 -> 16504 bytes src/testdir/samples/quickfix.txt | 4 + src/testdir/samples/re.freeze.txt | 6 + src/testdir/samples/test000 | Bin 0 -> 8 bytes src/testdir/sautest/autoload/Test104.vim | 1 + src/testdir/sautest/autoload/auto9.vim | 9 + src/testdir/sautest/autoload/foo.vim | 15 + src/testdir/sautest/autoload/footest.vim | 5 + src/testdir/sautest/autoload/globone.vim | 1 + src/testdir/sautest/autoload/globtwo.vim | 1 + src/testdir/sautest/autoload/sourced.vim | 4 + src/testdir/screendump.vim | 123 + src/testdir/script_util.vim | 69 + src/testdir/setup.vim | 39 + src/testdir/setup_gui.vim | 31 + src/testdir/shared.vim | 411 + src/testdir/silent.wav | Bin 0 -> 65580 bytes src/testdir/summarize.vim | 62 + src/testdir/term_util.vim | 196 + src/testdir/test10.in | 21 + src/testdir/test10.ok | 2 + src/testdir/test20.in | 27 + src/testdir/test20.ok | 10 + src/testdir/test21.in | 13 + src/testdir/test21.ok | 4 + src/testdir/test22.in | 15 + src/testdir/test22.ok | 2 + src/testdir/test23.in | Bin 0 -> 1301 bytes src/testdir/test23.ok | 32 + src/testdir/test24.in | Bin 0 -> 364 bytes src/testdir/test24.ok | 2 + src/testdir/test25.in | 108 + src/testdir/test25.ok | 99 + src/testdir/test26.in | 24 + src/testdir/test26.ok | 3 + src/testdir/test27.in | Bin 0 -> 2368 bytes src/testdir/test27.ok | Bin 0 -> 409 bytes src/testdir/test77a.com | 8 + src/testdir/test77a.in | 35 + src/testdir/test77a.ok | 1 + src/testdir/test_alot.vim | 31 + src/testdir/test_alot_latin.vim | 7 + src/testdir/test_alot_utf8.vim | 14 + src/testdir/test_arabic.vim | 595 + src/testdir/test_arglist.vim | 747 + src/testdir/test_assert.vim | 488 + src/testdir/test_autochdir.vim | 121 + src/testdir/test_autocmd.vim | 4270 +++++ src/testdir/test_autoload.vim | 30 + src/testdir/test_backspace_opt.vim | 141 + src/testdir/test_backup.vim | 88 + src/testdir/test_balloon.vim | 67 + src/testdir/test_balloon_gui.vim | 21 + src/testdir/test_behave.vim | 31 + src/testdir/test_bench_regexp.vim | 24 + src/testdir/test_blob.vim | 835 + src/testdir/test_blockedit.vim | 134 + src/testdir/test_breakindent.vim | 1055 ++ src/testdir/test_buffer.vim | 517 + src/testdir/test_bufline.vim | 341 + src/testdir/test_bufwintabinfo.vim | 197 + src/testdir/test_cd.vim | 247 + src/testdir/test_cdo.vim | 216 + src/testdir/test_changedtick.vim | 97 + src/testdir/test_changelist.vim | 105 + src/testdir/test_channel.py | 288 + src/testdir/test_channel.vim | 2696 +++ src/testdir/test_channel_6.py | 15 + src/testdir/test_channel_lsp.py | 333 + src/testdir/test_channel_pipe.py | 76 + src/testdir/test_channel_unix.py | 56 + src/testdir/test_channel_write.py | 18 + src/testdir/test_charsearch.vim | 98 + src/testdir/test_charsearch_utf8.vim | 19 + src/testdir/test_checkpath.vim | 116 + src/testdir/test_cindent.vim | 5442 ++++++ src/testdir/test_cjk_linebreak.vim | 101 + src/testdir/test_clientserver.vim | 196 + src/testdir/test_close_count.vim | 176 + src/testdir/test_cmd_lists.vim | 70 + src/testdir/test_cmdline.vim | 3447 ++++ src/testdir/test_cmdmods.vim | 45 + src/testdir/test_cmdwin.vim | 428 + src/testdir/test_codestyle.vim | 145 + src/testdir/test_command_count.vim | 198 + src/testdir/test_comments.vim | 277 + src/testdir/test_comparators.vim | 13 + src/testdir/test_compiler.vim | 89 + src/testdir/test_conceal.vim | 359 + src/testdir/test_const.vim | 335 + src/testdir/test_cpoptions.vim | 915 ++ src/testdir/test_crypt.vim | 288 + src/testdir/test_cscope.vim | 337 + src/testdir/test_cursor_func.vim | 493 + src/testdir/test_cursorline.vim | 327 + src/testdir/test_curswant.vim | 25 + src/testdir/test_debugger.vim | 1531 ++ src/testdir/test_delete.vim | 110 + src/testdir/test_diffmode.vim | 1630 ++ src/testdir/test_digraph.vim | 607 + src/testdir/test_display.vim | 471 + src/testdir/test_edit.vim | 2109 +++ src/testdir/test_environ.vim | 89 + src/testdir/test_erasebackword.vim | 22 + src/testdir/test_escaped_glob.vim | 35 + src/testdir/test_eval_stuff.vim | 705 + src/testdir/test_ex_equal.vim | 34 + src/testdir/test_ex_mode.vim | 290 + src/testdir/test_ex_undo.vim | 21 + src/testdir/test_ex_z.vim | 117 + src/testdir/test_excmd.vim | 728 + src/testdir/test_exec_while_if.vim | 43 + src/testdir/test_execute_func.vim | 207 + src/testdir/test_exists.vim | 337 + src/testdir/test_exists_autocmd.vim | 28 + src/testdir/test_exit.vim | 130 + src/testdir/test_expand.vim | 224 + src/testdir/test_expand_dllpath.vim | 36 + src/testdir/test_expand_func.vim | 144 + src/testdir/test_expr.vim | 1023 ++ src/testdir/test_expr_utf8.vim | 44 + src/testdir/test_file_perm.vim | 29 + src/testdir/test_file_size.vim | 61 + src/testdir/test_filechanged.vim | 264 + src/testdir/test_fileformat.vim | 327 + src/testdir/test_filetype.vim | 2023 +++ src/testdir/test_filter_cmd.vim | 199 + src/testdir/test_filter_map.vim | 234 + src/testdir/test_find_complete.vim | 164 + src/testdir/test_findfile.vim | 249 + src/testdir/test_fixeol.vim | 118 + src/testdir/test_flatten.vim | 109 + src/testdir/test_float_func.vim | 389 + src/testdir/test_fnameescape.vim | 27 + src/testdir/test_fnamemodify.vim | 106 + src/testdir/test_fold.vim | 1758 ++ src/testdir/test_function_lists.vim | 107 + src/testdir/test_functions.vim | 3078 ++++ src/testdir/test_ga.vim | 44 + src/testdir/test_getcwd.vim | 268 + src/testdir/test_getvar.vim | 163 + src/testdir/test_gf.vim | 295 + src/testdir/test_glob2regpat.vim | 35 + src/testdir/test_global.vim | 150 + src/testdir/test_gn.vim | 221 + src/testdir/test_goto.vim | 441 + src/testdir/test_gui.vim | 1684 ++ src/testdir/test_gui_init.vim | 46 + src/testdir/test_hardcopy.vim | 212 + src/testdir/test_help.vim | 209 + src/testdir/test_help_tagjump.vim | 318 + src/testdir/test_hide.vim | 97 + src/testdir/test_highlight.vim | 1301 ++ src/testdir/test_history.vim | 252 + src/testdir/test_hlsearch.vim | 94 + src/testdir/test_iminsert.vim | 326 + src/testdir/test_increment.vim | 896 + src/testdir/test_increment_dbcs.vim | 28 + src/testdir/test_indent.vim | 278 + src/testdir/test_input.vim | 61 + src/testdir/test_ins_complete.vim | 2224 +++ src/testdir/test_ins_complete_no_halt.vim | 51 + src/testdir/test_interrupt.vim | 32 + src/testdir/test_job_fails.vim | 17 + src/testdir/test_join.vim | 448 + src/testdir/test_json.vim | 329 + src/testdir/test_jumplist.vim | 101 + src/testdir/test_lambda.vim | 384 + src/testdir/test_langmap.vim | 89 + src/testdir/test_largefile.vim | 31 + src/testdir/test_let.vim | 616 + src/testdir/test_lineending.vim | 22 + src/testdir/test_lispindent.vim | 129 + src/testdir/test_listchars.vim | 693 + src/testdir/test_listdict.vim | 1529 ++ src/testdir/test_listener.vim | 453 + src/testdir/test_listlbr.vim | 334 + src/testdir/test_listlbr_utf8.vim | 284 + src/testdir/test_lua.vim | 1235 ++ src/testdir/test_makeencoding.py | 67 + src/testdir/test_makeencoding.vim | 120 + src/testdir/test_man.vim | 149 + src/testdir/test_map_functions.vim | 584 + src/testdir/test_mapping.vim | 1817 ++ src/testdir/test_marks.vim | 321 + src/testdir/test_match.vim | 437 + src/testdir/test_matchadd_conceal.vim | 426 + src/testdir/test_matchadd_conceal_utf8.vim | 45 + src/testdir/test_matchfuzzy.vim | 256 + src/testdir/test_memory_usage.vim | 165 + src/testdir/test_menu.vim | 597 + src/testdir/test_messages.vim | 593 + src/testdir/test_method.vim | 175 + src/testdir/test_mksession.vim | 1265 ++ src/testdir/test_mksession_utf8.vim | 105 + src/testdir/test_modeless.vim | 407 + src/testdir/test_modeline.vim | 361 + src/testdir/test_move.vim | 70 + src/testdir/test_mswin_event.vim | 1006 ++ src/testdir/test_mzscheme.vim | 62 + src/testdir/test_nested_function.vim | 70 + src/testdir/test_netbeans.py | 210 + src/testdir/test_netbeans.vim | 973 ++ src/testdir/test_normal.vim | 3924 +++++ src/testdir/test_number.vim | 357 + src/testdir/test_options.vim | 1673 ++ src/testdir/test_packadd.vim | 446 + src/testdir/test_partial.vim | 409 + src/testdir/test_paste.vim | 338 + src/testdir/test_perl.vim | 356 + src/testdir/test_plus_arg_edit.vim | 45 + src/testdir/test_popup.vim | 1253 ++ src/testdir/test_popupwin.vim | 4183 +++++ src/testdir/test_popupwin_textprop.vim | 173 + src/testdir/test_preview.vim | 63 + src/testdir/test_profile.vim | 772 + src/testdir/test_prompt_buffer.vim | 255 + src/testdir/test_put.vim | 246 + src/testdir/test_python2.vim | 3788 +++++ src/testdir/test_python3.vim | 4114 +++++ src/testdir/test_pyx2.vim | 103 + src/testdir/test_pyx3.vim | 103 + src/testdir/test_quickfix.vim | 6408 ++++++++ src/testdir/test_quotestar.vim | 158 + src/testdir/test_random.vim | 56 + src/testdir/test_recover.vim | 451 + src/testdir/test_regex_char_classes.vim | 297 + src/testdir/test_regexp_latin.vim | 1163 ++ src/testdir/test_regexp_utf8.vim | 579 + src/testdir/test_registers.vim | 890 + src/testdir/test_reltime.vim | 31 + src/testdir/test_rename.vim | 113 + src/testdir/test_restricted.vim | 120 + src/testdir/test_retab.vim | 117 + src/testdir/test_ruby.vim | 437 + src/testdir/test_scriptnames.vim | 96 + src/testdir/test_scroll_opt.vim | 608 + src/testdir/test_scrollbind.vim | 275 + src/testdir/test_search.vim | 2174 +++ src/testdir/test_search_stat.vim | 436 + src/testdir/test_searchpos.vim | 30 + src/testdir/test_selectmode.vim | 313 + src/testdir/test_set.vim | 78 + src/testdir/test_sha256.vim | 24 + src/testdir/test_shell.vim | 298 + src/testdir/test_shift.vim | 115 + src/testdir/test_short_sleep.py | 11 + src/testdir/test_shortpathname.vim | 99 + src/testdir/test_signals.vim | 205 + src/testdir/test_signs.vim | 2062 +++ src/testdir/test_sleep.vim | 27 + src/testdir/test_smartindent.vim | 159 + src/testdir/test_sort.vim | 1561 ++ src/testdir/test_sound.vim | 100 + src/testdir/test_source.vim | 677 + src/testdir/test_source_utf8.vim | 63 + src/testdir/test_spell.vim | 1505 ++ src/testdir/test_spell_utf8.vim | 831 + src/testdir/test_spellfile.vim | 1156 ++ src/testdir/test_startup.vim | 1355 ++ src/testdir/test_startup_utf8.vim | 81 + src/testdir/test_stat.vim | 224 + src/testdir/test_statusline.vim | 613 + src/testdir/test_substitute.vim | 1427 ++ src/testdir/test_suspend.vim | 121 + src/testdir/test_swap.vim | 576 + src/testdir/test_syn_attr.vim | 834 + src/testdir/test_syntax.vim | 981 ++ src/testdir/test_system.vim | 146 + src/testdir/test_tab.vim | 92 + src/testdir/test_tabline.vim | 205 + src/testdir/test_tabpage.vim | 890 + src/testdir/test_tagcase.vim | 75 + src/testdir/test_tagfunc.vim | 416 + src/testdir/test_tagjump.vim | 1548 ++ src/testdir/test_taglist.vim | 263 + src/testdir/test_tcl.vim | 752 + src/testdir/test_termcodes.vim | 2726 +++ src/testdir/test_termencoding.vim | 38 + src/testdir/test_terminal.vim | 2353 +++ src/testdir/test_terminal2.vim | 570 + src/testdir/test_terminal3.vim | 935 ++ src/testdir/test_terminal_fail.vim | 22 + src/testdir/test_textformat.vim | 1306 ++ src/testdir/test_textobjects.vim | 644 + src/testdir/test_textprop.vim | 3884 +++++ src/testdir/test_timers.vim | 544 + src/testdir/test_true_false.vim | 154 + src/testdir/test_trycatch.vim | 2351 +++ src/testdir/test_undo.vim | 807 + src/testdir/test_unlet.vim | 67 + src/testdir/test_user_func.vim | 802 + src/testdir/test_usercommands.vim | 938 ++ src/testdir/test_utf8.vim | 331 + src/testdir/test_utf8_comparisons.vim | 96 + src/testdir/test_vartabs.vim | 458 + src/testdir/test_version.vim | 26 + src/testdir/test_vim9_assign.vim | 2825 ++++ src/testdir/test_vim9_builtin.vim | 4949 ++++++ src/testdir/test_vim9_class.vim | 1752 ++ src/testdir/test_vim9_cmd.vim | 2040 +++ src/testdir/test_vim9_disassemble.vim | 3049 ++++ src/testdir/test_vim9_expr.vim | 4160 +++++ src/testdir/test_vim9_fails.vim | 62 + src/testdir/test_vim9_func.vim | 4576 ++++++ src/testdir/test_vim9_import.vim | 2923 ++++ src/testdir/test_vim9_script.vim | 4573 ++++++ src/testdir/test_viminfo.vim | 1282 ++ src/testdir/test_vimscript.vim | 7534 +++++++++ src/testdir/test_virtualedit.vim | 612 + src/testdir/test_visual.vim | 1558 ++ src/testdir/test_winbar.vim | 190 + src/testdir/test_winbuf_close.vim | 228 + src/testdir/test_window_cmd.vim | 1952 +++ src/testdir/test_window_id.vim | 142 + src/testdir/test_windows_home.vim | 122 + src/testdir/test_wnext.vim | 103 + src/testdir/test_wordcount.vim | 106 + src/testdir/test_writefile.vim | 980 ++ src/testdir/test_xxd.vim | 404 + .../testluaplugin/lua/testluaplugin/hello.lua | 7 + .../testluaplugin/lua/testluaplugin/init.lua | 5 + src/testdir/thread_util.py | 90 + src/testdir/unix.vim | 13 + src/testdir/view_util.vim | 117 + src/testdir/vim9.vim | 275 + src/testdir/vms.vim | 6 + src/testing.c | 1578 ++ src/textformat.c | 1210 ++ src/textobject.c | 2004 +++ src/textprop.c | 2451 +++ src/time.c | 1155 ++ src/toolbar.phi | 1283 ++ src/toolcheck | 36 + src/tools.bmp | Bin 0 -> 4660 bytes src/typemap | 14 + src/typval.c | 2741 ++++ src/ui.c | 1269 ++ src/undo.c | 3750 +++++ src/uninstall.c | 426 + src/usercmd.c | 1969 +++ src/userfunc.c | 6956 ++++++++ src/version.c | 4116 +++++ src/version.h | 50 + src/vim.h | 2888 ++++ src/vim.ico | Bin 0 -> 28786 bytes src/vim.manifest | 59 + src/vim.rc | 136 + src/vim.tlb | Bin 0 -> 1792 bytes src/vim9.h | 873 + src/vim9class.c | 1653 ++ src/vim9cmds.c | 2653 +++ src/vim9compile.c | 4021 +++++ src/vim9execute.c | 7394 +++++++++ src/vim9expr.c | 3530 ++++ src/vim9instr.c | 2750 ++++ src/vim9script.c | 1148 ++ src/vim9type.c | 1754 ++ src/vim_alert.ico | Bin 0 -> 1078 bytes src/vim_error.ico | Bin 0 -> 1078 bytes src/vim_icon.xbm | 14 + src/vim_info.ico | Bin 0 -> 1078 bytes src/vim_mask.xbm | 14 + src/vim_quest.ico | Bin 0 -> 1078 bytes src/viminfo.c | 3325 ++++ src/vimrun.c | 113 + src/vimtutor | 74 + src/which.sh | 12 + src/winclip.c | 774 + src/window.c | 7721 +++++++++ src/xdiff/COPYING | 504 + src/xdiff/README.txt | 19 + src/xdiff/xdiff.h | 158 + src/xdiff/xdiffi.c | 1101 ++ src/xdiff/xdiffi.h | 64 + src/xdiff/xemit.c | 348 + src/xdiff/xemit.h | 36 + src/xdiff/xhistogram.c | 386 + src/xdiff/xinclude.h | 71 + src/xdiff/xmacros.h | 54 + src/xdiff/xpatience.c | 386 + src/xdiff/xprepare.c | 483 + src/xdiff/xprepare.h | 34 + src/xdiff/xtypes.h | 67 + src/xdiff/xutils.c | 434 + src/xdiff/xutils.h | 47 + src/xpm/COPYRIGHT | 31 + src/xpm/README.txt | 30 + src/xpm/arm64/lib-vc14/libXpm.lib | Bin 0 -> 127884 bytes src/xpm/include/simx.h | 139 + src/xpm/include/xpm.h | 501 + src/xpm/x64/lib-vc14/libXpm.lib | Bin 0 -> 121904 bytes src/xpm/x64/lib/libXpm.a | Bin 0 -> 73758 bytes src/xpm/x86/lib-vc14/libXpm.lib | Bin 0 -> 86422 bytes src/xpm/x86/lib/libXpm.a | Bin 0 -> 66414 bytes src/xpm_w32.c | 56 + src/xpm_w32.h | 7 + src/xxd/Make_amiga.mak | 18 + src/xxd/Make_ming.mak | 28 + src/xxd/Make_mvc.mak | 19 + src/xxd/Make_vms.mms | 72 + src/xxd/Makefile | 7 + src/xxd/xxd.c | 891 + 1853 files changed, 1118098 insertions(+) create mode 100644 src/GvimExt/GvimExt.reg create mode 100644 src/GvimExt/Make_ming.mak create mode 100644 src/GvimExt/Make_mvc.mak create mode 100644 src/GvimExt/Makefile create mode 100644 src/GvimExt/README.txt create mode 100644 src/GvimExt/gvimext.cpp create mode 100644 src/GvimExt/gvimext.def create mode 100644 src/GvimExt/gvimext.h create mode 100644 src/GvimExt/gvimext.inf create mode 100644 src/GvimExt/gvimext.rc create mode 100644 src/GvimExt/gvimext_ming.def create mode 100644 src/GvimExt/gvimext_ming.rc create mode 100644 src/GvimExt/resource.h create mode 100644 src/GvimExt/uninst.bat create mode 100644 src/INSTALL create mode 100644 src/INSTALLami.txt create mode 100644 src/INSTALLmac.txt create mode 100644 src/INSTALLpc.txt create mode 100644 src/INSTALLvms.txt create mode 100644 src/INSTALLx.txt create mode 100644 src/Make_all.mak create mode 100644 src/Make_ami.mak create mode 100644 src/Make_cyg.mak create mode 100644 src/Make_cyg_ming.mak create mode 100644 src/Make_ming.mak create mode 100644 src/Make_mvc.mak create mode 100644 src/Make_vms.mms create mode 100644 src/Makefile create mode 100644 src/README.md create mode 100644 src/alloc.c create mode 100644 src/alloc.h create mode 100644 src/arabic.c create mode 100644 src/arglist.c create mode 100644 src/ascii.h create mode 100755 src/auto/configure create mode 100644 src/autocmd.c create mode 100644 src/beval.c create mode 100644 src/beval.h create mode 100644 src/bigvim.bat create mode 100644 src/bigvim64.bat create mode 100644 src/blob.c create mode 100644 src/blowfish.c create mode 100644 src/buffer.c create mode 100644 src/bufwrite.c create mode 100644 src/change.c create mode 100644 src/channel.c create mode 100644 src/charset.c create mode 100644 src/cindent.c create mode 100644 src/clientserver.c create mode 100644 src/clipboard.c create mode 100644 src/cmdexpand.c create mode 100644 src/cmdhist.c create mode 100644 src/config.h.in create mode 100644 src/config.mk.dist create mode 100644 src/config.mk.in create mode 100755 src/configure create mode 100644 src/configure.ac create mode 100644 src/create_cmdidxs.vim create mode 100644 src/create_nvcmdidxs.c create mode 100644 src/create_nvcmdidxs.vim create mode 100644 src/crypt.c create mode 100644 src/crypt_zip.c create mode 100644 src/debugger.c create mode 100644 src/dict.c create mode 100644 src/diff.c create mode 100644 src/digraph.c create mode 100644 src/dlldata.c create mode 100644 src/dosinst.c create mode 100644 src/dosinst.h create mode 100644 src/drawline.c create mode 100644 src/drawscreen.c create mode 100644 src/edit.c create mode 100644 src/errors.h create mode 100644 src/eval.c create mode 100644 src/evalbuffer.c create mode 100644 src/evalfunc.c create mode 100644 src/evalvars.c create mode 100644 src/evalwindow.c create mode 100644 src/ex_cmdidxs.h create mode 100644 src/ex_cmds.c create mode 100644 src/ex_cmds.h create mode 100644 src/ex_cmds2.c create mode 100644 src/ex_docmd.c create mode 100644 src/ex_eval.c create mode 100644 src/ex_getln.c create mode 100644 src/feature.h create mode 100644 src/fileio.c create mode 100644 src/filepath.c create mode 100644 src/findfile.c create mode 100644 src/float.c create mode 100644 src/fold.c create mode 100644 src/getchar.c create mode 100644 src/globals.h create mode 100644 src/gui.c create mode 100644 src/gui.h create mode 100644 src/gui_beval.c create mode 100644 src/gui_dwrite.cpp create mode 100644 src/gui_dwrite.h create mode 100644 src/gui_gtk.c create mode 100644 src/gui_gtk_f.c create mode 100644 src/gui_gtk_f.h create mode 100644 src/gui_gtk_res.xml create mode 100644 src/gui_gtk_vms.h create mode 100644 src/gui_gtk_x11.c create mode 100644 src/gui_haiku.cc create mode 100644 src/gui_haiku.h create mode 100644 src/gui_motif.c create mode 100644 src/gui_photon.c create mode 100644 src/gui_w32.c create mode 100644 src/gui_w32_rc.h create mode 100644 src/gui_x11.c create mode 100644 src/gui_x11_pm.h create mode 100644 src/gui_xim.c create mode 100644 src/gui_xmdlg.c create mode 100644 src/gui_xmebw.c create mode 100644 src/gui_xmebw.h create mode 100644 src/gui_xmebwp.h create mode 100644 src/gvimtutor create mode 100644 src/hardcopy.c create mode 100644 src/hashtab.c create mode 100644 src/help.c create mode 100644 src/highlight.c create mode 100644 src/if_cscope.c create mode 100644 src/if_lua.c create mode 100644 src/if_mzsch.c create mode 100644 src/if_mzsch.h create mode 100644 src/if_ole.cpp create mode 100644 src/if_ole.h create mode 100644 src/if_ole.idl create mode 100644 src/if_perl.xs create mode 100644 src/if_perlsfio.c create mode 100644 src/if_py_both.h create mode 100644 src/if_python.c create mode 100644 src/if_python3.c create mode 100644 src/if_ruby.c create mode 100644 src/if_tcl.c create mode 100644 src/if_xcmdsrv.c create mode 100644 src/iid_ole.c create mode 100644 src/indent.c create mode 100644 src/insexpand.c create mode 100644 src/install-sh create mode 100755 src/installman.sh create mode 100644 src/installml.sh create mode 100644 src/iscygpty.c create mode 100644 src/iscygpty.h create mode 100644 src/job.c create mode 100644 src/json.c create mode 100644 src/json_test.c create mode 100644 src/keymap.h create mode 100644 src/kword_test.c create mode 100644 src/libvterm/.bzrignore create mode 100644 src/libvterm/.gitignore create mode 100644 src/libvterm/CONTRIBUTING create mode 100644 src/libvterm/LICENSE create mode 100644 src/libvterm/Makefile create mode 100644 src/libvterm/README create mode 100644 src/libvterm/doc/URLs create mode 100644 src/libvterm/doc/seqs.txt create mode 100644 src/libvterm/find-wide-chars.pl create mode 100644 src/libvterm/include/vterm.h create mode 100644 src/libvterm/include/vterm_keycodes.h create mode 100644 src/libvterm/src/encoding.c create mode 100644 src/libvterm/src/encoding/DECdrawing.inc create mode 100644 src/libvterm/src/encoding/DECdrawing.tbl create mode 100644 src/libvterm/src/encoding/uk.inc create mode 100644 src/libvterm/src/encoding/uk.tbl create mode 100644 src/libvterm/src/fullwidth.inc create mode 100644 src/libvterm/src/keyboard.c create mode 100644 src/libvterm/src/mouse.c create mode 100644 src/libvterm/src/parser.c create mode 100644 src/libvterm/src/pen.c create mode 100644 src/libvterm/src/rect.h create mode 100644 src/libvterm/src/screen.c create mode 100644 src/libvterm/src/state.c create mode 100644 src/libvterm/src/unicode.c create mode 100644 src/libvterm/src/utf8.h create mode 100644 src/libvterm/src/vterm.c create mode 100644 src/libvterm/src/vterm_internal.h create mode 100644 src/libvterm/t/02parser.test create mode 100644 src/libvterm/t/03encoding_utf8.test create mode 100644 src/libvterm/t/10state_putglyph.test create mode 100644 src/libvterm/t/11state_movecursor.test create mode 100644 src/libvterm/t/12state_scroll.test create mode 100644 src/libvterm/t/13state_edit.test create mode 100644 src/libvterm/t/14state_encoding.test create mode 100644 src/libvterm/t/15state_mode.test create mode 100644 src/libvterm/t/16state_resize.test create mode 100644 src/libvterm/t/17state_mouse.test create mode 100644 src/libvterm/t/18state_termprops.test create mode 100644 src/libvterm/t/20state_wrapping.test create mode 100644 src/libvterm/t/21state_tabstops.test create mode 100644 src/libvterm/t/22state_save.test create mode 100644 src/libvterm/t/25state_input.test create mode 100644 src/libvterm/t/26state_query.test create mode 100644 src/libvterm/t/27state_reset.test create mode 100644 src/libvterm/t/28state_dbl_wh.test create mode 100644 src/libvterm/t/29state_fallback.test create mode 100644 src/libvterm/t/30state_pen.test create mode 100644 src/libvterm/t/31state_rep.test create mode 100644 src/libvterm/t/32state_flow.test create mode 100644 src/libvterm/t/40state_selection.test create mode 100644 src/libvterm/t/60screen_ascii.test create mode 100644 src/libvterm/t/61screen_unicode.test create mode 100644 src/libvterm/t/62screen_damage.test create mode 100644 src/libvterm/t/63screen_resize.test create mode 100644 src/libvterm/t/64screen_pen.test create mode 100644 src/libvterm/t/65screen_protect.test create mode 100644 src/libvterm/t/66screen_extent.test create mode 100644 src/libvterm/t/67screen_dbl_wh.test create mode 100644 src/libvterm/t/68screen_termprops.test create mode 100644 src/libvterm/t/69screen_reflow.test create mode 100644 src/libvterm/t/90vttest_01-movement-1.test create mode 100644 src/libvterm/t/90vttest_01-movement-2.test create mode 100644 src/libvterm/t/90vttest_01-movement-3.test create mode 100644 src/libvterm/t/90vttest_01-movement-4.test create mode 100644 src/libvterm/t/90vttest_02-screen-1.test create mode 100644 src/libvterm/t/90vttest_02-screen-2.test create mode 100644 src/libvterm/t/90vttest_02-screen-3.test create mode 100644 src/libvterm/t/90vttest_02-screen-4.test create mode 100644 src/libvterm/t/92lp1640917.test create mode 100644 src/libvterm/t/harness.c create mode 100644 src/libvterm/t/run-test.pl create mode 100644 src/libvterm/tbl2inc_c.pl create mode 100644 src/libvterm/vterm.pc.in create mode 100644 src/link.390 create mode 100755 src/link.sh create mode 100644 src/list.c create mode 100644 src/locale.c create mode 100644 src/logfile.c create mode 100644 src/macros.h create mode 100644 src/main.c create mode 100644 src/map.c create mode 100644 src/mark.c create mode 100644 src/match.c create mode 100644 src/mbyte.c create mode 100644 src/memfile.c create mode 100644 src/memfile_test.c create mode 100644 src/memline.c create mode 100644 src/menu.c create mode 100644 src/message.c create mode 100644 src/message_test.c create mode 100644 src/misc1.c create mode 100644 src/misc2.c create mode 100644 src/mouse.c create mode 100644 src/move.c create mode 100644 src/msvc-latest.bat create mode 100644 src/msvc2015.bat create mode 100644 src/msvc2017.bat create mode 100644 src/msvc2019.bat create mode 100644 src/msvc2022.bat create mode 100755 src/msys32.bat create mode 100755 src/msys64.bat create mode 100644 src/mysign create mode 100644 src/nbdebug.c create mode 100644 src/nbdebug.h create mode 100644 src/netbeans.c create mode 100644 src/normal.c create mode 100644 src/nv_cmdidxs.h create mode 100644 src/nv_cmds.h create mode 100644 src/ops.c create mode 100644 src/option.c create mode 100644 src/option.h create mode 100644 src/optiondefs.h create mode 100644 src/optionstr.c create mode 100644 src/os_amiga.c create mode 100644 src/os_amiga.h create mode 100644 src/os_dos.h create mode 100644 src/os_haiku.h create mode 100644 src/os_haiku.rdef.in create mode 100644 src/os_mac.h create mode 100644 src/os_mac_conv.c create mode 100644 src/os_macosx.m create mode 100644 src/os_mswin.c create mode 100644 src/os_qnx.c create mode 100644 src/os_qnx.h create mode 100644 src/os_unix.c create mode 100644 src/os_unix.h create mode 100644 src/os_unixx.h create mode 100644 src/os_vms.c create mode 100644 src/os_vms_conf.h create mode 100644 src/os_vms_fix.com create mode 100644 src/os_vms_mms.c create mode 100644 src/os_w32dll.c create mode 100644 src/os_w32exe.c create mode 100644 src/os_win32.c create mode 100644 src/os_win32.h create mode 100755 src/osdef.sh create mode 100644 src/osdef1.h.in create mode 100644 src/osdef2.h.in create mode 100755 src/pathdef.sh create mode 100644 src/po/Make_all.mak create mode 100644 src/po/Make_cyg.mak create mode 100644 src/po/Make_ming.mak create mode 100644 src/po/Make_mvc.mak create mode 100644 src/po/Makefile create mode 100644 src/po/README.txt create mode 100644 src/po/README_mingw.txt create mode 100644 src/po/README_mvc.txt create mode 100644 src/po/af.po create mode 100644 src/po/ca.po create mode 100644 src/po/check.vim create mode 100644 src/po/cleanup.vim create mode 100644 src/po/cs.cp1250.po create mode 100644 src/po/cs.po create mode 100644 src/po/da.po create mode 100644 src/po/de.po create mode 100644 src/po/en_GB.po create mode 100644 src/po/eo.po create mode 100644 src/po/es.po create mode 100644 src/po/fi.po create mode 100644 src/po/fixfilenames.vim create mode 100644 src/po/fr.po create mode 100644 src/po/ga.po create mode 100644 src/po/gvim.desktop.in create mode 100644 src/po/it.po create mode 100644 src/po/ja.euc-jp.po create mode 100644 src/po/ja.po create mode 100644 src/po/ja.sjis.po create mode 100644 src/po/ko.UTF-8.po create mode 100644 src/po/ko.po create mode 100644 src/po/lv.po create mode 100644 src/po/nb.po create mode 100644 src/po/nl.po create mode 100644 src/po/no.po create mode 100644 src/po/pl.UTF-8.po create mode 100644 src/po/pl.cp1250.po create mode 100644 src/po/pl.po create mode 100644 src/po/pt_BR.po create mode 100644 src/po/ru.cp1251.po create mode 100644 src/po/ru.po create mode 100644 src/po/sjiscorr.c create mode 100644 src/po/sk.cp1250.po create mode 100644 src/po/sk.po create mode 100644 src/po/sr.po create mode 100644 src/po/sv.po create mode 100644 src/po/tojavascript.vim create mode 100644 src/po/tr.po create mode 100644 src/po/uk.cp1251.po create mode 100644 src/po/uk.po create mode 100644 src/po/vi.po create mode 100644 src/po/vim.desktop.in create mode 100644 src/po/zh_CN.UTF-8.po create mode 100644 src/po/zh_CN.cp936.po create mode 100644 src/po/zh_CN.po create mode 100644 src/po/zh_TW.UTF-8.po create mode 100644 src/po/zh_TW.po create mode 100644 src/popupmenu.c create mode 100644 src/popupwin.c create mode 100644 src/profiler.c create mode 100644 src/proto.h create mode 100644 src/proto/alloc.pro create mode 100644 src/proto/arabic.pro create mode 100644 src/proto/arglist.pro create mode 100644 src/proto/autocmd.pro create mode 100644 src/proto/beval.pro create mode 100644 src/proto/blob.pro create mode 100644 src/proto/blowfish.pro create mode 100644 src/proto/buffer.pro create mode 100644 src/proto/bufwrite.pro create mode 100644 src/proto/change.pro create mode 100644 src/proto/channel.pro create mode 100644 src/proto/charset.pro create mode 100644 src/proto/cindent.pro create mode 100644 src/proto/clientserver.pro create mode 100644 src/proto/clipboard.pro create mode 100644 src/proto/cmdexpand.pro create mode 100644 src/proto/cmdhist.pro create mode 100644 src/proto/crypt.pro create mode 100644 src/proto/crypt_zip.pro create mode 100644 src/proto/debugger.pro create mode 100644 src/proto/dict.pro create mode 100644 src/proto/diff.pro create mode 100644 src/proto/digraph.pro create mode 100644 src/proto/drawline.pro create mode 100644 src/proto/drawscreen.pro create mode 100644 src/proto/edit.pro create mode 100644 src/proto/eval.pro create mode 100644 src/proto/evalbuffer.pro create mode 100644 src/proto/evalfunc.pro create mode 100644 src/proto/evalvars.pro create mode 100644 src/proto/evalwindow.pro create mode 100644 src/proto/ex_cmds.pro create mode 100644 src/proto/ex_cmds2.pro create mode 100644 src/proto/ex_docmd.pro create mode 100644 src/proto/ex_eval.pro create mode 100644 src/proto/ex_getln.pro create mode 100644 src/proto/fileio.pro create mode 100644 src/proto/filepath.pro create mode 100644 src/proto/findfile.pro create mode 100644 src/proto/float.pro create mode 100644 src/proto/fold.pro create mode 100644 src/proto/getchar.pro create mode 100644 src/proto/gui.pro create mode 100644 src/proto/gui_beval.pro create mode 100644 src/proto/gui_gtk.pro create mode 100644 src/proto/gui_gtk_gresources.pro create mode 100644 src/proto/gui_gtk_x11.pro create mode 100644 src/proto/gui_haiku.pro create mode 100644 src/proto/gui_motif.pro create mode 100644 src/proto/gui_photon.pro create mode 100644 src/proto/gui_w32.pro create mode 100644 src/proto/gui_x11.pro create mode 100644 src/proto/gui_xim.pro create mode 100644 src/proto/gui_xmdlg.pro create mode 100644 src/proto/hardcopy.pro create mode 100644 src/proto/hashtab.pro create mode 100644 src/proto/help.pro create mode 100644 src/proto/highlight.pro create mode 100644 src/proto/if_cscope.pro create mode 100644 src/proto/if_lua.pro create mode 100644 src/proto/if_mzsch.pro create mode 100644 src/proto/if_ole.pro create mode 100644 src/proto/if_perl.pro create mode 100644 src/proto/if_perlsfio.pro create mode 100644 src/proto/if_python.pro create mode 100644 src/proto/if_python3.pro create mode 100644 src/proto/if_ruby.pro create mode 100644 src/proto/if_tcl.pro create mode 100644 src/proto/if_xcmdsrv.pro create mode 100644 src/proto/indent.pro create mode 100644 src/proto/insexpand.pro create mode 100644 src/proto/job.pro create mode 100644 src/proto/json.pro create mode 100644 src/proto/list.pro create mode 100644 src/proto/locale.pro create mode 100644 src/proto/logfile.pro create mode 100644 src/proto/main.pro create mode 100644 src/proto/map.pro create mode 100644 src/proto/mark.pro create mode 100644 src/proto/match.pro create mode 100644 src/proto/mbyte.pro create mode 100644 src/proto/memfile.pro create mode 100644 src/proto/memline.pro create mode 100644 src/proto/menu.pro create mode 100644 src/proto/message.pro create mode 100644 src/proto/misc1.pro create mode 100644 src/proto/misc2.pro create mode 100644 src/proto/mouse.pro create mode 100644 src/proto/move.pro create mode 100644 src/proto/netbeans.pro create mode 100644 src/proto/normal.pro create mode 100644 src/proto/ops.pro create mode 100644 src/proto/option.pro create mode 100644 src/proto/optionstr.pro create mode 100644 src/proto/os_amiga.pro create mode 100644 src/proto/os_mac_conv.pro create mode 100644 src/proto/os_macosx.pro create mode 100644 src/proto/os_mswin.pro create mode 100644 src/proto/os_qnx.pro create mode 100644 src/proto/os_unix.pro create mode 100644 src/proto/os_vms.pro create mode 100644 src/proto/os_win32.pro create mode 100644 src/proto/popupmenu.pro create mode 100644 src/proto/popupwin.pro create mode 100644 src/proto/profiler.pro create mode 100644 src/proto/pty.pro create mode 100644 src/proto/quickfix.pro create mode 100644 src/proto/regexp.pro create mode 100644 src/proto/register.pro create mode 100644 src/proto/screen.pro create mode 100644 src/proto/scriptfile.pro create mode 100644 src/proto/search.pro create mode 100644 src/proto/session.pro create mode 100644 src/proto/sha256.pro create mode 100644 src/proto/sign.pro create mode 100644 src/proto/sound.pro create mode 100644 src/proto/spell.pro create mode 100644 src/proto/spellfile.pro create mode 100644 src/proto/spellsuggest.pro create mode 100644 src/proto/strings.pro create mode 100644 src/proto/syntax.pro create mode 100644 src/proto/tag.pro create mode 100644 src/proto/term.pro create mode 100644 src/proto/terminal.pro create mode 100644 src/proto/termlib.pro create mode 100644 src/proto/testing.pro create mode 100644 src/proto/textformat.pro create mode 100644 src/proto/textobject.pro create mode 100644 src/proto/textprop.pro create mode 100644 src/proto/time.pro create mode 100644 src/proto/typval.pro create mode 100644 src/proto/ui.pro create mode 100644 src/proto/undo.pro create mode 100644 src/proto/usercmd.pro create mode 100644 src/proto/userfunc.pro create mode 100644 src/proto/version.pro create mode 100644 src/proto/vim9class.pro create mode 100644 src/proto/vim9cmds.pro create mode 100644 src/proto/vim9compile.pro create mode 100644 src/proto/vim9execute.pro create mode 100644 src/proto/vim9expr.pro create mode 100644 src/proto/vim9instr.pro create mode 100644 src/proto/vim9script.pro create mode 100644 src/proto/vim9type.pro create mode 100644 src/proto/viminfo.pro create mode 100644 src/proto/winclip.pro create mode 100644 src/proto/window.pro create mode 100644 src/protodef.h create mode 100644 src/pty.c create mode 100644 src/quickfix.c create mode 100644 src/regexp.c create mode 100644 src/regexp.h create mode 100644 src/regexp_bt.c create mode 100644 src/regexp_nfa.c create mode 100644 src/register.c create mode 100644 src/screen.c create mode 100644 src/scriptfile.c create mode 100644 src/search.c create mode 100644 src/session.c create mode 100644 src/sha256.c create mode 100644 src/sign.c create mode 100644 src/sound.c create mode 100644 src/spell.c create mode 100644 src/spell.h create mode 100644 src/spellfile.c create mode 100644 src/spellsuggest.c create mode 100644 src/strings.c create mode 100644 src/structs.h create mode 100644 src/syntax.c create mode 100644 src/tag.c create mode 100644 src/tearoff.bmp create mode 100644 src/tee/Make_ming.mak create mode 100644 src/tee/Make_mvc.mak create mode 100644 src/tee/Makefile create mode 100644 src/tee/tee.c create mode 100644 src/term.c create mode 100644 src/termdefs.h create mode 100644 src/terminal.c create mode 100644 src/termlib.c create mode 100644 src/testdir/Make_all.mak create mode 100644 src/testdir/Make_amiga.mak create mode 100644 src/testdir/Make_dos.mak create mode 100644 src/testdir/Make_ming.mak create mode 100644 src/testdir/Make_mvc.mak create mode 100644 src/testdir/Make_vms.mms create mode 100644 src/testdir/Makefile create mode 100644 src/testdir/README.txt create mode 100644 src/testdir/amiga.vim create mode 100644 src/testdir/check.vim create mode 100644 src/testdir/color_ramp.vim create mode 100644 src/testdir/dos.vim create mode 100644 src/testdir/dotest.in create mode 100644 src/testdir/dumps/Test_Xcursorline_1.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_10.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_11.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_12.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_13.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_14.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_15.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_16.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_17.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_18.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_19.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_2.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_20.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_21.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_22.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_23.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_24.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_3.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_4.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_5.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_6.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_7.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_8.dump create mode 100644 src/testdir/dumps/Test_Xcursorline_9.dump create mode 100644 src/testdir/dumps/Test_appendbufline_1.dump create mode 100644 src/testdir/dumps/Test_autocmd_nested_switch.dump create mode 100644 src/testdir/dumps/Test_balloon_eval_term_01.dump create mode 100644 src/testdir/dumps/Test_balloon_eval_term_01a.dump create mode 100644 src/testdir/dumps/Test_balloon_eval_term_02.dump create mode 100644 src/testdir/dumps/Test_changing_cmdheight_1.dump create mode 100644 src/testdir/dumps/Test_changing_cmdheight_2.dump create mode 100644 src/testdir/dumps/Test_changing_cmdheight_3.dump create mode 100644 src/testdir/dumps/Test_changing_cmdheight_4.dump create mode 100644 src/testdir/dumps/Test_changing_cmdheight_5.dump create mode 100644 src/testdir/dumps/Test_changing_cmdheight_6.dump create mode 100644 src/testdir/dumps/Test_cmdheight_tabline_1.dump create mode 100644 src/testdir/dumps/Test_cmdlineclear_tabenter.dump create mode 100644 src/testdir/dumps/Test_cmdwin_interrupted.dump create mode 100644 src/testdir/dumps/Test_cmdwin_no_terminal.dump create mode 100644 src/testdir/dumps/Test_cmdwin_restore_1.dump create mode 100644 src/testdir/dumps/Test_cmdwin_restore_2.dump create mode 100644 src/testdir/dumps/Test_cmdwin_restore_3.dump create mode 100644 src/testdir/dumps/Test_cmdwin_wrong_command_1.dump create mode 100644 src/testdir/dumps/Test_cmdwin_wrong_command_2.dump create mode 100644 src/testdir/dumps/Test_colorcolumn_1.dump create mode 100644 src/testdir/dumps/Test_colorcolumn_2.dump create mode 100644 src/testdir/dumps/Test_colorcolumn_3.dump create mode 100644 src/testdir/dumps/Test_conceal_cuc_01.dump create mode 100644 src/testdir/dumps/Test_conceal_cuc_02.dump create mode 100644 src/testdir/dumps/Test_conceal_cul_01.dump create mode 100644 src/testdir/dumps/Test_conceal_cul_02.dump create mode 100644 src/testdir/dumps/Test_conceal_cul_03.dump create mode 100644 src/testdir/dumps/Test_conceal_linebreak_1.dump create mode 100644 src/testdir/dumps/Test_conceal_resize_01.dump create mode 100644 src/testdir/dumps/Test_conceal_resize_02.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_01.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_02.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_03.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_04.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_05.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_06c.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_06i.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_06n.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_06v.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_07c.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_07i.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_07in.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_07n.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_07v.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_08c.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_08i.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_08n.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_08v.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_09c.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_09i.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_09n.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_09v.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_10.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_11.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_12.dump create mode 100644 src/testdir/dumps/Test_conceal_two_windows_13.dump create mode 100644 src/testdir/dumps/Test_cursor_position_with_showbreak.dump create mode 100644 src/testdir/dumps/Test_cursorcolumn_callback_1.dump create mode 100644 src/testdir/dumps/Test_cursorcolumn_insert_on_tab_1.dump create mode 100644 src/testdir/dumps/Test_cursorcolumn_insert_on_tab_2.dump create mode 100644 src/testdir/dumps/Test_cursorcolumn_insert_on_tab_3.dump create mode 100644 src/testdir/dumps/Test_cursorline_callback_1.dump create mode 100644 src/testdir/dumps/Test_cursorline_redraw_1.dump create mode 100644 src/testdir/dumps/Test_cursorline_redraw_2.dump create mode 100644 src/testdir/dumps/Test_cursorline_screenline_1.dump create mode 100644 src/testdir/dumps/Test_cursorline_screenline_2.dump create mode 100644 src/testdir/dumps/Test_cursorline_with_visualmode_01.dump create mode 100644 src/testdir/dumps/Test_cursorline_yank_01.dump create mode 100644 src/testdir/dumps/Test_diff_01.dump create mode 100644 src/testdir/dumps/Test_diff_02.dump create mode 100644 src/testdir/dumps/Test_diff_03.dump create mode 100644 src/testdir/dumps/Test_diff_04.dump create mode 100644 src/testdir/dumps/Test_diff_05.dump create mode 100644 src/testdir/dumps/Test_diff_06.0.dump create mode 100644 src/testdir/dumps/Test_diff_06.1.dump create mode 100644 src/testdir/dumps/Test_diff_06.2.dump create mode 100644 src/testdir/dumps/Test_diff_06.dump create mode 100644 src/testdir/dumps/Test_diff_07.dump create mode 100644 src/testdir/dumps/Test_diff_08.dump create mode 100644 src/testdir/dumps/Test_diff_09.dump create mode 100644 src/testdir/dumps/Test_diff_10.dump create mode 100644 src/testdir/dumps/Test_diff_11.dump create mode 100644 src/testdir/dumps/Test_diff_12.dump create mode 100644 src/testdir/dumps/Test_diff_13.dump create mode 100644 src/testdir/dumps/Test_diff_14.dump create mode 100644 src/testdir/dumps/Test_diff_15.dump create mode 100644 src/testdir/dumps/Test_diff_16.dump create mode 100644 src/testdir/dumps/Test_diff_17.dump create mode 100644 src/testdir/dumps/Test_diff_18.dump create mode 100644 src/testdir/dumps/Test_diff_19.dump create mode 100644 src/testdir/dumps/Test_diff_20.dump create mode 100644 src/testdir/dumps/Test_diff_bin_01.dump create mode 100644 src/testdir/dumps/Test_diff_bin_02.dump create mode 100644 src/testdir/dumps/Test_diff_bin_03.dump create mode 100644 src/testdir/dumps/Test_diff_bin_04.dump create mode 100644 src/testdir/dumps/Test_diff_cuc_01.dump create mode 100644 src/testdir/dumps/Test_diff_cuc_02.dump create mode 100644 src/testdir/dumps/Test_diff_cuc_03.dump create mode 100644 src/testdir/dumps/Test_diff_cuc_04.dump create mode 100644 src/testdir/dumps/Test_diff_of_diff_01.dump create mode 100644 src/testdir/dumps/Test_diff_of_diff_02.dump create mode 100644 src/testdir/dumps/Test_diff_rnu_01.dump create mode 100644 src/testdir/dumps/Test_diff_rnu_02.dump create mode 100644 src/testdir/dumps/Test_diff_rnu_03.dump create mode 100644 src/testdir/dumps/Test_diff_scroll_1.dump create mode 100644 src/testdir/dumps/Test_diff_scroll_2.dump create mode 100644 src/testdir/dumps/Test_diff_scroll_change_01.dump create mode 100644 src/testdir/dumps/Test_diff_scroll_change_02.dump create mode 100644 src/testdir/dumps/Test_diff_scroll_change_03.dump create mode 100644 src/testdir/dumps/Test_diff_syntax_1.dump create mode 100644 src/testdir/dumps/Test_diff_with_cul_bri_01.dump create mode 100644 src/testdir/dumps/Test_diff_with_cul_bri_02.dump create mode 100644 src/testdir/dumps/Test_diff_with_cul_bri_03.dump create mode 100644 src/testdir/dumps/Test_diff_with_cul_bri_04.dump create mode 100644 src/testdir/dumps/Test_diff_with_cursorline_01.dump create mode 100644 src/testdir/dumps/Test_diff_with_cursorline_02.dump create mode 100644 src/testdir/dumps/Test_diff_with_cursorline_03.dump create mode 100644 src/testdir/dumps/Test_diff_with_cursorline_number_01.dump create mode 100644 src/testdir/dumps/Test_diff_with_cursorline_number_02.dump create mode 100644 src/testdir/dumps/Test_display_fillchars_1.dump create mode 100644 src/testdir/dumps/Test_display_fillchars_2.dump create mode 100644 src/testdir/dumps/Test_display_lastline_1.dump create mode 100644 src/testdir/dumps/Test_display_lastline_2.dump create mode 100644 src/testdir/dumps/Test_display_lastline_3.dump create mode 100644 src/testdir/dumps/Test_display_lastline_4.dump create mode 100644 src/testdir/dumps/Test_display_lastline_5.dump create mode 100644 src/testdir/dumps/Test_display_lastline_6.dump create mode 100644 src/testdir/dumps/Test_display_lastline_euro_1.dump create mode 100644 src/testdir/dumps/Test_display_lastline_euro_2.dump create mode 100644 src/testdir/dumps/Test_display_lastline_euro_3.dump create mode 100644 src/testdir/dumps/Test_display_lastline_euro_4.dump create mode 100644 src/testdir/dumps/Test_display_lastline_euro_5.dump create mode 100644 src/testdir/dumps/Test_display_lastline_euro_6.dump create mode 100644 src/testdir/dumps/Test_display_scroll_at_topline.dump create mode 100644 src/testdir/dumps/Test_display_scroll_update_visual.dump create mode 100644 src/testdir/dumps/Test_display_unprintable_01.dump create mode 100644 src/testdir/dumps/Test_display_unprintable_02.dump create mode 100644 src/testdir/dumps/Test_display_visual_block_scroll.dump create mode 100644 src/testdir/dumps/Test_echowin_eval.dump create mode 100644 src/testdir/dumps/Test_echowin_showmode.dump create mode 100644 src/testdir/dumps/Test_echowindow_1.dump create mode 100644 src/testdir/dumps/Test_echowindow_2.dump create mode 100644 src/testdir/dumps/Test_echowindow_3.dump create mode 100644 src/testdir/dumps/Test_echowindow_4.dump create mode 100644 src/testdir/dumps/Test_echowindow_5.dump create mode 100644 src/testdir/dumps/Test_echowindow_6.dump create mode 100644 src/testdir/dumps/Test_echowindow_7.dump create mode 100644 src/testdir/dumps/Test_echowindow_8.dump create mode 100644 src/testdir/dumps/Test_echowindow_9.dump create mode 100644 src/testdir/dumps/Test_fileinfo_after_echo.dump create mode 100644 src/testdir/dumps/Test_folds_with_rnu_01.dump create mode 100644 src/testdir/dumps/Test_folds_with_rnu_02.dump create mode 100644 src/testdir/dumps/Test_functions_echoraw.dump create mode 100644 src/testdir/dumps/Test_hlsearch_1.dump create mode 100644 src/testdir/dumps/Test_hlsearch_2.dump create mode 100644 src/testdir/dumps/Test_hlsearch_block_visual_match.dump create mode 100644 src/testdir/dumps/Test_hlsearch_ctrlr_1.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_changed_1.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_multiple_line_1.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_multiple_line_2.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_multiple_line_3.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_multiple_line_4.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_multiple_line_5.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_single_line_1.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_single_line_2.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_single_line_2a.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_single_line_2b.dump create mode 100644 src/testdir/dumps/Test_hlsearch_cursearch_single_line_3.dump create mode 100644 src/testdir/dumps/Test_hlsearch_visual_1.dump create mode 100644 src/testdir/dumps/Test_hor_scroll_1.dump create mode 100644 src/testdir/dumps/Test_hor_scroll_2.dump create mode 100644 src/testdir/dumps/Test_hor_scroll_3.dump create mode 100644 src/testdir/dumps/Test_hor_scroll_4.dump create mode 100644 src/testdir/dumps/Test_hor_scroll_5.dump create mode 100644 src/testdir/dumps/Test_incsearch_change_01.dump create mode 100644 src/testdir/dumps/Test_incsearch_newline1.dump create mode 100644 src/testdir/dumps/Test_incsearch_newline2.dump create mode 100644 src/testdir/dumps/Test_incsearch_newline3.dump create mode 100644 src/testdir/dumps/Test_incsearch_newline4.dump create mode 100644 src/testdir/dumps/Test_incsearch_newline5.dump create mode 100644 src/testdir/dumps/Test_incsearch_scrolling_01.dump create mode 100644 src/testdir/dumps/Test_incsearch_search_01.dump create mode 100644 src/testdir/dumps/Test_incsearch_search_02.dump create mode 100644 src/testdir/dumps/Test_incsearch_sort_01.dump create mode 100644 src/testdir/dumps/Test_incsearch_sort_02.dump create mode 100644 src/testdir/dumps/Test_incsearch_sub_01.dump create mode 100644 src/testdir/dumps/Test_incsearch_sub_02.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_01.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_02.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_03.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_04.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_05.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_06.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_07.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_08.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_09.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_10.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_11.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_12.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_13.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_14.dump create mode 100644 src/testdir/dumps/Test_incsearch_substitute_15.dump create mode 100644 src/testdir/dumps/Test_incsearch_vimgrep_01.dump create mode 100644 src/testdir/dumps/Test_incsearch_vimgrep_02.dump create mode 100644 src/testdir/dumps/Test_incsearch_vimgrep_03.dump create mode 100644 src/testdir/dumps/Test_incsearch_vimgrep_04.dump create mode 100644 src/testdir/dumps/Test_incsearch_vimgrep_05.dump create mode 100644 src/testdir/dumps/Test_job_buffer_scroll_1.dump create mode 100644 src/testdir/dumps/Test_keytyped_in_nested_func.dump create mode 100644 src/testdir/dumps/Test_linebreak_reset_restore_1.dump create mode 100644 src/testdir/dumps/Test_listchars_01.dump create mode 100644 src/testdir/dumps/Test_listchars_02.dump create mode 100644 src/testdir/dumps/Test_listchars_03.dump create mode 100644 src/testdir/dumps/Test_listchars_04.dump create mode 100644 src/testdir/dumps/Test_listchars_05.dump create mode 100644 src/testdir/dumps/Test_listchars_06.dump create mode 100644 src/testdir/dumps/Test_listchars_07.dump create mode 100644 src/testdir/dumps/Test_long_file_name_1.dump create mode 100644 src/testdir/dumps/Test_long_text_with_padding_1.dump create mode 100644 src/testdir/dumps/Test_long_text_with_padding_2.dump create mode 100644 src/testdir/dumps/Test_map_expr_1.dump create mode 100644 src/testdir/dumps/Test_map_expr_2.dump create mode 100644 src/testdir/dumps/Test_map_expr_3.dump create mode 100644 src/testdir/dumps/Test_map_expr_4.dump create mode 100644 src/testdir/dumps/Test_map_list_1.dump create mode 100644 src/testdir/dumps/Test_match_linebreak.dump create mode 100644 src/testdir/dumps/Test_match_tab_linebreak.dump create mode 100644 src/testdir/dumps/Test_match_with_incsearch_1.dump create mode 100644 src/testdir/dumps/Test_match_with_incsearch_2.dump create mode 100644 src/testdir/dumps/Test_matchadd_1.dump create mode 100644 src/testdir/dumps/Test_matchaddpos_1.dump create mode 100644 src/testdir/dumps/Test_matchclear_1.dump create mode 100644 src/testdir/dumps/Test_matchdelete_1.dump create mode 100644 src/testdir/dumps/Test_matchparen_clear_highlight_1.dump create mode 100644 src/testdir/dumps/Test_matchparen_clear_highlight_2.dump create mode 100644 src/testdir/dumps/Test_misplaced_type.dump create mode 100644 src/testdir/dumps/Test_mode_updated_1.dump create mode 100644 src/testdir/dumps/Test_more_scrollback_1.dump create mode 100644 src/testdir/dumps/Test_more_scrollback_2.dump create mode 100644 src/testdir/dumps/Test_move_undo_1.dump create mode 100644 src/testdir/dumps/Test_move_undo_2.dump create mode 100644 src/testdir/dumps/Test_popup_and_previewwindow_01.dump create mode 100644 src/testdir/dumps/Test_popup_command_01.dump create mode 100644 src/testdir/dumps/Test_popup_command_02.dump create mode 100644 src/testdir/dumps/Test_popup_command_03.dump create mode 100644 src/testdir/dumps/Test_popup_command_04.dump create mode 100644 src/testdir/dumps/Test_popup_command_05.dump create mode 100644 src/testdir/dumps/Test_popup_position_01.dump create mode 100644 src/testdir/dumps/Test_popup_position_02.dump create mode 100644 src/testdir/dumps/Test_popup_position_03.dump create mode 100644 src/testdir/dumps/Test_popup_position_04.dump create mode 100644 src/testdir/dumps/Test_popup_prop_not_visible_01.dump create mode 100644 src/testdir/dumps/Test_popup_prop_not_visible_01a.dump create mode 100644 src/testdir/dumps/Test_popup_prop_not_visible_01b.dump create mode 100644 src/testdir/dumps/Test_popup_prop_not_visible_02.dump create mode 100644 src/testdir/dumps/Test_popup_prop_not_visible_03.dump create mode 100644 src/testdir/dumps/Test_popup_settext_01.dump create mode 100644 src/testdir/dumps/Test_popup_settext_02.dump create mode 100644 src/testdir/dumps/Test_popup_settext_03.dump create mode 100644 src/testdir/dumps/Test_popup_settext_04.dump create mode 100644 src/testdir/dumps/Test_popup_settext_05.dump create mode 100644 src/testdir/dumps/Test_popup_settext_06.dump create mode 100644 src/testdir/dumps/Test_popup_settext_07.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_01.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_02.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_03.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_04.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_05.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_06.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_07.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_corn_1.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_corn_2.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_corn_3.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_corn_4.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_corn_5.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_corn_6.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_off_1.dump create mode 100644 src/testdir/dumps/Test_popup_textprop_off_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_02.dump create mode 100644 src/testdir/dumps/Test_popupwin_03.dump create mode 100644 src/testdir/dumps/Test_popupwin_04.dump create mode 100644 src/testdir/dumps/Test_popupwin_04a.dump create mode 100644 src/testdir/dumps/Test_popupwin_05.dump create mode 100644 src/testdir/dumps/Test_popupwin_06.dump create mode 100644 src/testdir/dumps/Test_popupwin_07.dump create mode 100644 src/testdir/dumps/Test_popupwin_08.dump create mode 100644 src/testdir/dumps/Test_popupwin_10.dump create mode 100644 src/testdir/dumps/Test_popupwin_11.dump create mode 100644 src/testdir/dumps/Test_popupwin_20.dump create mode 100644 src/testdir/dumps/Test_popupwin_21.dump create mode 100644 src/testdir/dumps/Test_popupwin_22.dump create mode 100644 src/testdir/dumps/Test_popupwin_23.dump create mode 100644 src/testdir/dumps/Test_popupwin_24.dump create mode 100644 src/testdir/dumps/Test_popupwin_atcursor_pos.dump create mode 100644 src/testdir/dumps/Test_popupwin_behind.dump create mode 100644 src/testdir/dumps/Test_popupwin_beval_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_beval_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_beval_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_close_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_close_02.dump create mode 100644 src/testdir/dumps/Test_popupwin_close_03.dump create mode 100644 src/testdir/dumps/Test_popupwin_close_04.dump create mode 100644 src/testdir/dumps/Test_popupwin_close_05.dump create mode 100644 src/testdir/dumps/Test_popupwin_corners.dump create mode 100644 src/testdir/dumps/Test_popupwin_ctrl_c.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_4.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_5.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_6.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_7.dump create mode 100644 src/testdir/dumps/Test_popupwin_cursorline_8.dump create mode 100644 src/testdir/dumps/Test_popupwin_doublewidth_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_drag_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_drag_02.dump create mode 100644 src/testdir/dumps/Test_popupwin_drag_03.dump create mode 100644 src/testdir/dumps/Test_popupwin_drag_04.dump create mode 100644 src/testdir/dumps/Test_popupwin_drag_05.dump create mode 100644 src/testdir/dumps/Test_popupwin_drag_06.dump create mode 100644 src/testdir/dumps/Test_popupwin_drag_minwidth_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_drag_minwidth_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_drag_minwidth_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_firstline_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_firstline_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_4.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_5.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_6.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_7.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_8.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_9.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_align_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_align_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_align_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_hidden_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_hidden_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_hidden_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_nb_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_infopopup_wide_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_longtitle_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_longtitle_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_longtitle_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_longtitle_4.dump create mode 100644 src/testdir/dumps/Test_popupwin_mask_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_mask_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_mask_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_mask_4.dump create mode 100644 src/testdir/dumps/Test_popupwin_mask_5.dump create mode 100644 src/testdir/dumps/Test_popupwin_matches.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_02.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_03.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_04.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_filter_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_filter_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_filter_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_filter_4.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_filter_5.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_maxwidth_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_scroll_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_scroll_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_scroll_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_scroll_4.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_scroll_5.dump create mode 100644 src/testdir/dumps/Test_popupwin_menu_scroll_6.dump create mode 100644 src/testdir/dumps/Test_popupwin_multibytetitle.dump create mode 100644 src/testdir/dumps/Test_popupwin_normal_cmd.dump create mode 100644 src/testdir/dumps/Test_popupwin_nospace.dump create mode 100644 src/testdir/dumps/Test_popupwin_notify_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_notify_02.dump create mode 100644 src/testdir/dumps/Test_popupwin_nowrap.dump create mode 100644 src/testdir/dumps/Test_popupwin_poptermscroll_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_poptermscroll_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_poptermscroll_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_poptermscroll_4.dump create mode 100644 src/testdir/dumps/Test_popupwin_popupmenu_masking_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_popupmenu_masking_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_10.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_4.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_5.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_6.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_7.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_8.dump create mode 100644 src/testdir/dumps/Test_popupwin_previewpopup_9.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_10.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_11.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_12.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_13.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_4.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_5.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_6.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_7.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_8.dump create mode 100644 src/testdir/dumps/Test_popupwin_scroll_9.dump create mode 100644 src/testdir/dumps/Test_popupwin_select_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_select_02.dump create mode 100644 src/testdir/dumps/Test_popupwin_set_firstline_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_set_firstline_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_showbreak.dump create mode 100644 src/testdir/dumps/Test_popupwin_sign_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_sign_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_term_01.dump create mode 100644 src/testdir/dumps/Test_popupwin_term_02.dump create mode 100644 src/testdir/dumps/Test_popupwin_term_03.dump create mode 100644 src/testdir/dumps/Test_popupwin_term_04.dump create mode 100644 src/testdir/dumps/Test_popupwin_three_errors_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_three_errors_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_title.dump create mode 100644 src/testdir/dumps/Test_popupwin_toohigh_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_toohigh_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_toohigh_3.dump create mode 100644 src/testdir/dumps/Test_popupwin_win_execute.dump create mode 100644 src/testdir/dumps/Test_popupwin_win_execute_cursorline.dump create mode 100644 src/testdir/dumps/Test_popupwin_wrap.dump create mode 100644 src/testdir/dumps/Test_popupwin_wrap_1.dump create mode 100644 src/testdir/dumps/Test_popupwin_wrap_2.dump create mode 100644 src/testdir/dumps/Test_popupwin_wrong_name.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_empty_1.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_empty_2.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_empty_3.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_empty_4.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_empty_5.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_1.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_10.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_11.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_12.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_13.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_14.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_15.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_16.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_2.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_3.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_4.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_5.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_6.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_7.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_8.dump create mode 100644 src/testdir/dumps/Test_prop_above_below_smoothscroll_9.dump create mode 100644 src/testdir/dumps/Test_prop_above_empty_1.dump create mode 100644 src/testdir/dumps/Test_prop_above_empty_2.dump create mode 100644 src/testdir/dumps/Test_prop_above_number_1.dump create mode 100644 src/testdir/dumps/Test_prop_above_number_2.dump create mode 100644 src/testdir/dumps/Test_prop_after_linebreak.dump create mode 100644 src/testdir/dumps/Test_prop_after_tab.dump create mode 100644 src/testdir/dumps/Test_prop_at_same_pos.dump create mode 100644 src/testdir/dumps/Test_prop_before_tab_01.dump create mode 100644 src/testdir/dumps/Test_prop_before_tab_02.dump create mode 100644 src/testdir/dumps/Test_prop_before_tab_03.dump create mode 100644 src/testdir/dumps/Test_prop_before_tab_04.dump create mode 100644 src/testdir/dumps/Test_prop_before_tab_05.dump create mode 100644 src/testdir/dumps/Test_prop_before_tab_06.dump create mode 100644 src/testdir/dumps/Test_prop_before_tab_07.dump create mode 100644 src/testdir/dumps/Test_prop_before_tab_08.dump create mode 100644 src/testdir/dumps/Test_prop_before_tab_09.dump create mode 100644 src/testdir/dumps/Test_prop_before_tab_10.dump create mode 100644 src/testdir/dumps/Test_prop_below_after_empty_1.dump create mode 100644 src/testdir/dumps/Test_prop_below_after_empty_2.dump create mode 100644 src/testdir/dumps/Test_prop_below_after_empty_3.dump create mode 100644 src/testdir/dumps/Test_prop_below_split_line_1.dump create mode 100644 src/testdir/dumps/Test_prop_below_split_line_2.dump create mode 100644 src/testdir/dumps/Test_prop_below_split_line_3.dump create mode 100644 src/testdir/dumps/Test_prop_delete_updates_1.dump create mode 100644 src/testdir/dumps/Test_prop_delete_updates_2.dump create mode 100644 src/testdir/dumps/Test_prop_delete_updates_3.dump create mode 100644 src/testdir/dumps/Test_prop_diff_mode_1.dump create mode 100644 src/testdir/dumps/Test_prop_diff_mode_2.dump create mode 100644 src/testdir/dumps/Test_prop_insert_list_mode_1.dump create mode 100644 src/testdir/dumps/Test_prop_insert_list_mode_2.dump create mode 100644 src/testdir/dumps/Test_prop_insert_list_mode_3.dump create mode 100644 src/testdir/dumps/Test_prop_insert_start_incl_1.dump create mode 100644 src/testdir/dumps/Test_prop_insert_start_incl_2.dump create mode 100644 src/testdir/dumps/Test_prop_insert_start_incl_3.dump create mode 100644 src/testdir/dumps/Test_prop_insert_start_incl_4.dump create mode 100644 src/testdir/dumps/Test_prop_insert_start_incl_5.dump create mode 100644 src/testdir/dumps/Test_prop_insert_start_incl_6.dump create mode 100644 src/testdir/dumps/Test_prop_insert_start_incl_7.dump create mode 100644 src/testdir/dumps/Test_prop_insert_start_incl_8.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_1.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_2.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_3.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_4.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_5.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_6.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_hi_1.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_hi_2.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_hi_3.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_hi_4.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_hi_5.dump create mode 100644 src/testdir/dumps/Test_prop_inserts_text_hi_6.dump create mode 100644 src/testdir/dumps/Test_prop_linebreak_1.dump create mode 100644 src/testdir/dumps/Test_prop_linebreak_2.dump create mode 100644 src/testdir/dumps/Test_prop_multibyte_below_1.dump create mode 100644 src/testdir/dumps/Test_prop_negative_error_1.dump create mode 100644 src/testdir/dumps/Test_prop_negative_error_2.dump create mode 100644 src/testdir/dumps/Test_prop_right_align_twice_1.dump create mode 100644 src/testdir/dumps/Test_prop_right_align_twice_2.dump create mode 100644 src/testdir/dumps/Test_prop_right_align_twice_3.dump create mode 100644 src/testdir/dumps/Test_prop_text_change_arg_1.dump create mode 100644 src/testdir/dumps/Test_prop_text_change_arg_2.dump create mode 100644 src/testdir/dumps/Test_prop_text_with_padding_1.dump create mode 100644 src/testdir/dumps/Test_prop_text_with_padding_2.dump create mode 100644 src/testdir/dumps/Test_prop_text_with_padding_3.dump create mode 100644 src/testdir/dumps/Test_prop_text_with_padding_4.dump create mode 100644 src/testdir/dumps/Test_prop_with_linebreak_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_linebreak_2.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_1a.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_1b.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_1c.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_2.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_3.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_4.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_5.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_6.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_7.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_8.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_above_9.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_below_trunc_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_below_trunc_2.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_below_trunc_3.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_join_split_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_join_split_2.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_join_split_3.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_join_split_4.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_join_split_5.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_joined_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_nowrap_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_nowrap_2.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_nowrap_3.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_trunc_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_trunc_2.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_trunc_3.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_trunc_4.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_trunc_5.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_after_wraps_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_below_after_match_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_below_cul_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_below_nowrap_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_below_nowrap_2.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_cursormoved_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_cursormoved_2.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_empty_line_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_empty_line_2.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_empty_line_3.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_empty_line_4.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_empty_line_5.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_override_1.dump create mode 100644 src/testdir/dumps/Test_prop_with_text_override_2.dump create mode 100644 src/testdir/dumps/Test_prop_with_wrap_1.dump create mode 100644 src/testdir/dumps/Test_props_after_1.dump create mode 100644 src/testdir/dumps/Test_props_after_2.dump create mode 100644 src/testdir/dumps/Test_pum_preview_1.dump create mode 100644 src/testdir/dumps/Test_pum_preview_2.dump create mode 100644 src/testdir/dumps/Test_pum_preview_3.dump create mode 100644 src/testdir/dumps/Test_pum_preview_4.dump create mode 100644 src/testdir/dumps/Test_pum_rightleft_01.dump create mode 100644 src/testdir/dumps/Test_pum_rightleft_02.dump create mode 100644 src/testdir/dumps/Test_pum_scrollbar_01.dump create mode 100644 src/testdir/dumps/Test_pum_scrollbar_02.dump create mode 100644 src/testdir/dumps/Test_pum_stopped_by_timer.dump create mode 100644 src/testdir/dumps/Test_pum_with_folds_two_tabs.dump create mode 100644 src/testdir/dumps/Test_pum_with_preview_win.dump create mode 100644 src/testdir/dumps/Test_quickfix_cwindow_1.dump create mode 100644 src/testdir/dumps/Test_quickfix_cwindow_2.dump create mode 100644 src/testdir/dumps/Test_quickfix_cwindow_3.dump create mode 100644 src/testdir/dumps/Test_quickfix_cwindow_4.dump create mode 100644 src/testdir/dumps/Test_quickfix_window_fails.dump create mode 100644 src/testdir/dumps/Test_quit_long_message.dump create mode 100644 src/testdir/dumps/Test_redraw_in_autocmd_1.dump create mode 100644 src/testdir/dumps/Test_redraw_in_autocmd_2.dump create mode 100644 src/testdir/dumps/Test_redrawstatus_in_autocmd_1.dump create mode 100644 src/testdir/dumps/Test_redrawstatus_in_autocmd_2.dump create mode 100644 src/testdir/dumps/Test_redrawstatus_in_autocmd_3.dump create mode 100644 src/testdir/dumps/Test_redrawstatus_in_autocmd_4.dump create mode 100644 src/testdir/dumps/Test_redrawstatus_in_autocmd_5.dump create mode 100644 src/testdir/dumps/Test_relativenumber_callback_1.dump create mode 100644 src/testdir/dumps/Test_relnr_colors_1.dump create mode 100644 src/testdir/dumps/Test_relnr_colors_2.dump create mode 100644 src/testdir/dumps/Test_relnr_colors_3.dump create mode 100644 src/testdir/dumps/Test_relnr_colors_4.dump create mode 100644 src/testdir/dumps/Test_scroll_no_region_1.dump create mode 100644 src/testdir/dumps/Test_scroll_no_region_2.dump create mode 100644 src/testdir/dumps/Test_scroll_no_region_3.dump create mode 100644 src/testdir/dumps/Test_scroll_no_region_4.dump create mode 100644 src/testdir/dumps/Test_scroll_no_region_5.dump create mode 100644 src/testdir/dumps/Test_scroll_no_region_6.dump create mode 100644 src/testdir/dumps/Test_scrollbar_on_wide_char.dump create mode 100644 src/testdir/dumps/Test_searchstat_1.dump create mode 100644 src/testdir/dumps/Test_searchstat_2.dump create mode 100644 src/testdir/dumps/Test_searchstat_3.dump create mode 100644 src/testdir/dumps/Test_searchstat_4.dump create mode 100644 src/testdir/dumps/Test_searchstat_inc_1.dump create mode 100644 src/testdir/dumps/Test_searchstat_inc_2.dump create mode 100644 src/testdir/dumps/Test_searchstat_inc_3.dump create mode 100644 src/testdir/dumps/Test_searchstatgd_1.dump create mode 100644 src/testdir/dumps/Test_searchstatgd_2.dump create mode 100644 src/testdir/dumps/Test_setcellwidths_dump_1.dump create mode 100644 src/testdir/dumps/Test_setcellwidths_dump_2.dump create mode 100644 src/testdir/dumps/Test_sign_cursor_1.dump create mode 100644 src/testdir/dumps/Test_sign_cursor_2.dump create mode 100644 src/testdir/dumps/Test_sign_cursor_3.dump create mode 100644 src/testdir/dumps/Test_sign_cursor_4.dump create mode 100644 src/testdir/dumps/Test_sign_cursor_5.dump create mode 100644 src/testdir/dumps/Test_sign_cursor_6.dump create mode 100644 src/testdir/dumps/Test_smooth_diff_1.dump create mode 100644 src/testdir/dumps/Test_smooth_list_1.dump create mode 100644 src/testdir/dumps/Test_smooth_list_2.dump create mode 100644 src/testdir/dumps/Test_smooth_long_1.dump create mode 100644 src/testdir/dumps/Test_smooth_long_10.dump create mode 100644 src/testdir/dumps/Test_smooth_long_11.dump create mode 100644 src/testdir/dumps/Test_smooth_long_12.dump create mode 100644 src/testdir/dumps/Test_smooth_long_13.dump create mode 100644 src/testdir/dumps/Test_smooth_long_14.dump create mode 100644 src/testdir/dumps/Test_smooth_long_15.dump create mode 100644 src/testdir/dumps/Test_smooth_long_2.dump create mode 100644 src/testdir/dumps/Test_smooth_long_3.dump create mode 100644 src/testdir/dumps/Test_smooth_long_4.dump create mode 100644 src/testdir/dumps/Test_smooth_long_5.dump create mode 100644 src/testdir/dumps/Test_smooth_long_6.dump create mode 100644 src/testdir/dumps/Test_smooth_long_7.dump create mode 100644 src/testdir/dumps/Test_smooth_long_8.dump create mode 100644 src/testdir/dumps/Test_smooth_long_9.dump create mode 100644 src/testdir/dumps/Test_smooth_long_showbreak_1.dump create mode 100644 src/testdir/dumps/Test_smooth_long_showbreak_2.dump create mode 100644 src/testdir/dumps/Test_smooth_number_1.dump create mode 100644 src/testdir/dumps/Test_smooth_number_2.dump create mode 100644 src/testdir/dumps/Test_smooth_number_3.dump create mode 100644 src/testdir/dumps/Test_smooth_number_4.dump create mode 100644 src/testdir/dumps/Test_smooth_number_5.dump create mode 100644 src/testdir/dumps/Test_smooth_number_6.dump create mode 100644 src/testdir/dumps/Test_smooth_number_7.dump create mode 100644 src/testdir/dumps/Test_smooth_one_long_1.dump create mode 100644 src/testdir/dumps/Test_smooth_one_long_2.dump create mode 100644 src/testdir/dumps/Test_smooth_wrap_1.dump create mode 100644 src/testdir/dumps/Test_smooth_wrap_2.dump create mode 100644 src/testdir/dumps/Test_smooth_wrap_3.dump create mode 100644 src/testdir/dumps/Test_smooth_wrap_4.dump create mode 100644 src/testdir/dumps/Test_smooth_wrap_5.dump create mode 100644 src/testdir/dumps/Test_smooth_wrap_6.dump create mode 100644 src/testdir/dumps/Test_smoothscroll_1.dump create mode 100644 src/testdir/dumps/Test_smoothscroll_2.dump create mode 100644 src/testdir/dumps/Test_smoothscroll_3.dump create mode 100644 src/testdir/dumps/Test_smoothscroll_4.dump create mode 100644 src/testdir/dumps/Test_smoothscroll_5.dump create mode 100644 src/testdir/dumps/Test_smoothscroll_6.dump create mode 100644 src/testdir/dumps/Test_smoothscroll_7.dump create mode 100644 src/testdir/dumps/Test_smoothscroll_8.dump create mode 100644 src/testdir/dumps/Test_smoothscroll_zero_1.dump create mode 100644 src/testdir/dumps/Test_smoothscroll_zero_2.dump create mode 100644 src/testdir/dumps/Test_spell_1.dump create mode 100644 src/testdir/dumps/Test_spell_2.dump create mode 100644 src/testdir/dumps/Test_spell_3.dump create mode 100644 src/testdir/dumps/Test_spell_4.dump create mode 100644 src/testdir/dumps/Test_spell_5.dump create mode 100644 src/testdir/dumps/Test_spell_compatible_1.dump create mode 100644 src/testdir/dumps/Test_spell_compatible_2.dump create mode 100644 src/testdir/dumps/Test_splitkeep_callback_1.dump create mode 100644 src/testdir/dumps/Test_splitkeep_callback_2.dump create mode 100644 src/testdir/dumps/Test_splitkeep_callback_3.dump create mode 100644 src/testdir/dumps/Test_splitkeep_callback_4.dump create mode 100644 src/testdir/dumps/Test_splitkeep_fold_1.dump create mode 100644 src/testdir/dumps/Test_splitkeep_fold_2.dump create mode 100644 src/testdir/dumps/Test_splitkeep_fold_3.dump create mode 100644 src/testdir/dumps/Test_splitkeep_fold_4.dump create mode 100644 src/testdir/dumps/Test_splitkeep_status_1.dump create mode 100644 src/testdir/dumps/Test_start_with_tabs.dump create mode 100644 src/testdir/dumps/Test_statusline_1.dump create mode 100644 src/testdir/dumps/Test_statusline_hl.dump create mode 100644 src/testdir/dumps/Test_statusline_mode_1.dump create mode 100644 src/testdir/dumps/Test_statusline_mode_2.dump create mode 100644 src/testdir/dumps/Test_statusline_showcmd_1.dump create mode 100644 src/testdir/dumps/Test_statusline_showcmd_2.dump create mode 100644 src/testdir/dumps/Test_statusline_showcmd_3.dump create mode 100644 src/testdir/dumps/Test_statusline_showcmd_4.dump create mode 100644 src/testdir/dumps/Test_statusline_showcmd_5.dump create mode 100644 src/testdir/dumps/Test_sub_highlight_zer_match_1.dump create mode 100644 src/testdir/dumps/Test_syntax_c_01.dump create mode 100644 src/testdir/dumps/Test_tabline_showcmd_1.dump create mode 100644 src/testdir/dumps/Test_tabline_showcmd_2.dump create mode 100644 src/testdir/dumps/Test_tabline_showcmd_3.dump create mode 100644 src/testdir/dumps/Test_tabline_showcmd_4.dump create mode 100644 src/testdir/dumps/Test_tabline_showcmd_5.dump create mode 100644 src/testdir/dumps/Test_tabpage_cmdheight.dump create mode 100644 src/testdir/dumps/Test_tenc_euc_jp_01.dump create mode 100644 src/testdir/dumps/Test_term_popup_bufline.dump create mode 100644 src/testdir/dumps/Test_terminal_all_ansi_colors.dump create mode 100644 src/testdir/dumps/Test_terminal_color_MyTermCol.dump create mode 100644 src/testdir/dumps/Test_terminal_color_MyTermCol_over_Terminal.dump create mode 100644 src/testdir/dumps/Test_terminal_color_MyWinCol.dump create mode 100644 src/testdir/dumps/Test_terminal_color_MyWinCol_over_group.dump create mode 100644 src/testdir/dumps/Test_terminal_color_Terminal.dump create mode 100644 src/testdir/dumps/Test_terminal_color_gui_MyTermCol.dump create mode 100644 src/testdir/dumps/Test_terminal_color_gui_MyWinCol.dump create mode 100644 src/testdir/dumps/Test_terminal_color_gui_Terminal.dump create mode 100644 src/testdir/dumps/Test_terminal_color_gui_transp_MyTermCol.dump create mode 100644 src/testdir/dumps/Test_terminal_color_gui_transp_MyWinCol.dump create mode 100644 src/testdir/dumps/Test_terminal_color_gui_transp_Terminal.dump create mode 100644 src/testdir/dumps/Test_terminal_color_transp_MyTermCol.dump create mode 100644 src/testdir/dumps/Test_terminal_color_transp_MyWinCol.dump create mode 100644 src/testdir/dumps/Test_terminal_color_transp_Terminal.dump create mode 100644 src/testdir/dumps/Test_terminal_combining.dump create mode 100644 src/testdir/dumps/Test_terminal_dumpload.dump create mode 100644 src/testdir/dumps/Test_terminal_focus_1.dump create mode 100644 src/testdir/dumps/Test_terminal_focus_2.dump create mode 100644 src/testdir/dumps/Test_terminal_focus_3.dump create mode 100644 src/testdir/dumps/Test_terminal_from_cmd.dump create mode 100644 src/testdir/dumps/Test_terminal_normal_1.dump create mode 100644 src/testdir/dumps/Test_terminal_normal_2.dump create mode 100644 src/testdir/dumps/Test_terminal_normal_3.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_1.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_2.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_3.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_4.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_5.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_6.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_7.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_8.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_MyPopupHlCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_MyTermCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_MyTermCol_over_Terminal.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_MyWinCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_MyWinCol_over_group.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_Terminal.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_gui_MyPopupHlCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_gui_MyTermCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_gui_MyWinCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_gui_Terminal.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_gui_transp_MyPopupHlCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_gui_transp_MyTermCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_gui_transp_MyWinCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_gui_transp_Terminal.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_m1.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_transp_MyPopupHlCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_transp_MyTermCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_transp_MyWinCol.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_transp_Terminal.dump create mode 100644 src/testdir/dumps/Test_terminal_scrollback_1.dump create mode 100644 src/testdir/dumps/Test_terminal_scrollback_2.dump create mode 100644 src/testdir/dumps/Test_terminal_scrollback_3.dump create mode 100644 src/testdir/dumps/Test_terminal_wincolor_split_MyWinCol.dump create mode 100644 src/testdir/dumps/Test_terminal_wincolor_split_MyWinCol2.dump create mode 100644 src/testdir/dumps/Test_text_after_nowrap_1.dump create mode 100644 src/testdir/dumps/Test_text_after_nowrap_2.dump create mode 100644 src/testdir/dumps/Test_text_after_nowrap_3.dump create mode 100644 src/testdir/dumps/Test_text_after_nowrap_4.dump create mode 100644 src/testdir/dumps/Test_text_after_nowrap_5.dump create mode 100644 src/testdir/dumps/Test_text_after_nowrap_list_1.dump create mode 100644 src/testdir/dumps/Test_text_below_nowrap_1.dump create mode 100644 src/testdir/dumps/Test_textprop_01.dump create mode 100644 src/testdir/dumps/Test_textprop_hl_override_1.dump create mode 100644 src/testdir/dumps/Test_textprop_hl_override_2.dump create mode 100644 src/testdir/dumps/Test_textprop_nesting.dump create mode 100644 src/testdir/dumps/Test_textprop_nowrap_01.dump create mode 100644 src/testdir/dumps/Test_textprop_nowrap_02.dump create mode 100644 src/testdir/dumps/Test_textprop_syn_1.dump create mode 100644 src/testdir/dumps/Test_textprop_tab.dump create mode 100644 src/testdir/dumps/Test_textprop_vis_01.dump create mode 100644 src/testdir/dumps/Test_textprop_vis_02.dump create mode 100644 src/testdir/dumps/Test_tselect_1.dump create mode 100644 src/testdir/dumps/Test_undo_after_write_1.dump create mode 100644 src/testdir/dumps/Test_undo_after_write_2.dump create mode 100644 src/testdir/dumps/Test_undo_after_write_2.vim create mode 100644 src/testdir/dumps/Test_verbose_option_1.dump create mode 100644 src/testdir/dumps/Test_verbose_system_1.dump create mode 100644 src/testdir/dumps/Test_verbose_system_1.vim create mode 100644 src/testdir/dumps/Test_verbose_system_2.dump create mode 100644 src/testdir/dumps/Test_verbose_system_2.vim create mode 100644 src/testdir/dumps/Test_vim9_closure_fails.dump create mode 100644 src/testdir/dumps/Test_vim9_no_redraw.dump create mode 100644 src/testdir/dumps/Test_vim9_reject_declaration_1.dump create mode 100644 src/testdir/dumps/Test_vim9_reject_declaration_2.dump create mode 100644 src/testdir/dumps/Test_vim9_silent_echo.dump create mode 100644 src/testdir/dumps/Test_virtual_text_in_popup_highlight_1.dump create mode 100644 src/testdir/dumps/Test_visual_block_with_virtualedit.dump create mode 100644 src/testdir/dumps/Test_visual_block_with_virtualedit2.dump create mode 100644 src/testdir/dumps/Test_wildmenu_1.dump create mode 100644 src/testdir/dumps/Test_wildmenu_2.dump create mode 100644 src/testdir/dumps/Test_wildmenu_3.dump create mode 100644 src/testdir/dumps/Test_wildmenu_4.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_01.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_02.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_03.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_04.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_05.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_06.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_07.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_08.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_09.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_10.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_11.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_12.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_13.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_14.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_15.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_16.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_17.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_18.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_19.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_20.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_21.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_22.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_23.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_24.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_25.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_26.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_27.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_28.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_29.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_30.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_31.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_32.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_33.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_34.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_35.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_36.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_37.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_38.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_39.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_40.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_41.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_42.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_43.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_44.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_45.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_46.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_47.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_48.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_49.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_50.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_clear_entries_1.dump create mode 100644 src/testdir/dumps/Test_wildmenu_pum_term_01.dump create mode 100644 src/testdir/dumps/Test_wildmenu_with_pum_foldexpr_1.dump create mode 100644 src/testdir/dumps/Test_wildmenu_with_pum_foldexpr_2.dump create mode 100644 src/testdir/dumps/Test_win_gotoid_1.dump create mode 100644 src/testdir/dumps/Test_win_gotoid_2.dump create mode 100644 src/testdir/dumps/Test_win_gotoid_3.dump create mode 100644 src/testdir/dumps/Test_winbar_not_visible.dump create mode 100644 src/testdir/dumps/Test_winbar_not_visible_custom_statusline.dump create mode 100644 src/testdir/dumps/Test_wincolor_01.dump create mode 100644 src/testdir/dumps/Test_wincolor_lcs.dump create mode 100644 src/testdir/dumps/Test_winline_rnu.dump create mode 100644 src/testdir/dumps/Test_winscrolled_not_when_defined_1.dump create mode 100644 src/testdir/dumps/Test_winscrolled_not_when_defined_2.dump create mode 100644 src/testdir/dumps/Test_winscrolled_once_only_1.dump create mode 100644 src/testdir/gen_opt_test.vim create mode 100644 src/testdir/gui_init.vim create mode 100644 src/testdir/gui_preinit.vim create mode 100644 src/testdir/keycode_check.json create mode 100644 src/testdir/keycode_check.vim create mode 100644 src/testdir/lsan-suppress.txt create mode 100644 src/testdir/mouse.vim create mode 100644 src/testdir/popupbounce.vim create mode 100644 src/testdir/python2/module.py create mode 100644 src/testdir/python3/module.py create mode 100644 src/testdir/python_after/after.py create mode 100644 src/testdir/python_before/before.py create mode 100644 src/testdir/python_before/before_1.py create mode 100644 src/testdir/python_before/before_2.py create mode 100644 src/testdir/pythonx/failing.py create mode 100644 src/testdir/pythonx/failing_import.py create mode 100644 src/testdir/pythonx/module.py create mode 100644 src/testdir/pythonx/modulex.py create mode 100644 src/testdir/pythonx/topmodule/__init__.py create mode 100644 src/testdir/pythonx/topmodule/submodule/__init__.py create mode 100644 src/testdir/pythonx/topmodule/submodule/subsubmodule/__init__.py create mode 100644 src/testdir/pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py create mode 100644 src/testdir/pyxfile/py2_magic.py create mode 100644 src/testdir/pyxfile/py2_shebang.py create mode 100644 src/testdir/pyxfile/py3_magic.py create mode 100644 src/testdir/pyxfile/py3_shebang.py create mode 100644 src/testdir/pyxfile/pyx.py create mode 100644 src/testdir/runtest.vim create mode 100644 src/testdir/samples/crypt_sodium_invalid.txt create mode 100644 src/testdir/samples/quickfix.txt create mode 100644 src/testdir/samples/re.freeze.txt create mode 100644 src/testdir/samples/test000 create mode 100644 src/testdir/sautest/autoload/Test104.vim create mode 100644 src/testdir/sautest/autoload/auto9.vim create mode 100644 src/testdir/sautest/autoload/foo.vim create mode 100644 src/testdir/sautest/autoload/footest.vim create mode 100644 src/testdir/sautest/autoload/globone.vim create mode 100644 src/testdir/sautest/autoload/globtwo.vim create mode 100644 src/testdir/sautest/autoload/sourced.vim create mode 100644 src/testdir/screendump.vim create mode 100644 src/testdir/script_util.vim create mode 100644 src/testdir/setup.vim create mode 100644 src/testdir/setup_gui.vim create mode 100644 src/testdir/shared.vim create mode 100644 src/testdir/silent.wav create mode 100644 src/testdir/summarize.vim create mode 100644 src/testdir/term_util.vim create mode 100644 src/testdir/test10.in create mode 100644 src/testdir/test10.ok create mode 100644 src/testdir/test20.in create mode 100644 src/testdir/test20.ok create mode 100644 src/testdir/test21.in create mode 100644 src/testdir/test21.ok create mode 100644 src/testdir/test22.in create mode 100644 src/testdir/test22.ok create mode 100644 src/testdir/test23.in create mode 100644 src/testdir/test23.ok create mode 100644 src/testdir/test24.in create mode 100644 src/testdir/test24.ok create mode 100644 src/testdir/test25.in create mode 100644 src/testdir/test25.ok create mode 100644 src/testdir/test26.in create mode 100644 src/testdir/test26.ok create mode 100644 src/testdir/test27.in create mode 100644 src/testdir/test27.ok create mode 100644 src/testdir/test77a.com create mode 100644 src/testdir/test77a.in create mode 100644 src/testdir/test77a.ok create mode 100644 src/testdir/test_alot.vim create mode 100644 src/testdir/test_alot_latin.vim create mode 100644 src/testdir/test_alot_utf8.vim create mode 100644 src/testdir/test_arabic.vim create mode 100644 src/testdir/test_arglist.vim create mode 100644 src/testdir/test_assert.vim create mode 100644 src/testdir/test_autochdir.vim create mode 100644 src/testdir/test_autocmd.vim create mode 100644 src/testdir/test_autoload.vim create mode 100644 src/testdir/test_backspace_opt.vim create mode 100644 src/testdir/test_backup.vim create mode 100644 src/testdir/test_balloon.vim create mode 100644 src/testdir/test_balloon_gui.vim create mode 100644 src/testdir/test_behave.vim create mode 100644 src/testdir/test_bench_regexp.vim create mode 100644 src/testdir/test_blob.vim create mode 100644 src/testdir/test_blockedit.vim create mode 100644 src/testdir/test_breakindent.vim create mode 100644 src/testdir/test_buffer.vim create mode 100644 src/testdir/test_bufline.vim create mode 100644 src/testdir/test_bufwintabinfo.vim create mode 100644 src/testdir/test_cd.vim create mode 100644 src/testdir/test_cdo.vim create mode 100644 src/testdir/test_changedtick.vim create mode 100644 src/testdir/test_changelist.vim create mode 100644 src/testdir/test_channel.py create mode 100644 src/testdir/test_channel.vim create mode 100644 src/testdir/test_channel_6.py create mode 100644 src/testdir/test_channel_lsp.py create mode 100644 src/testdir/test_channel_pipe.py create mode 100644 src/testdir/test_channel_unix.py create mode 100644 src/testdir/test_channel_write.py create mode 100644 src/testdir/test_charsearch.vim create mode 100644 src/testdir/test_charsearch_utf8.vim create mode 100644 src/testdir/test_checkpath.vim create mode 100644 src/testdir/test_cindent.vim create mode 100644 src/testdir/test_cjk_linebreak.vim create mode 100644 src/testdir/test_clientserver.vim create mode 100644 src/testdir/test_close_count.vim create mode 100644 src/testdir/test_cmd_lists.vim create mode 100644 src/testdir/test_cmdline.vim create mode 100644 src/testdir/test_cmdmods.vim create mode 100644 src/testdir/test_cmdwin.vim create mode 100644 src/testdir/test_codestyle.vim create mode 100644 src/testdir/test_command_count.vim create mode 100644 src/testdir/test_comments.vim create mode 100644 src/testdir/test_comparators.vim create mode 100644 src/testdir/test_compiler.vim create mode 100644 src/testdir/test_conceal.vim create mode 100644 src/testdir/test_const.vim create mode 100644 src/testdir/test_cpoptions.vim create mode 100644 src/testdir/test_crypt.vim create mode 100644 src/testdir/test_cscope.vim create mode 100644 src/testdir/test_cursor_func.vim create mode 100644 src/testdir/test_cursorline.vim create mode 100644 src/testdir/test_curswant.vim create mode 100644 src/testdir/test_debugger.vim create mode 100644 src/testdir/test_delete.vim create mode 100644 src/testdir/test_diffmode.vim create mode 100644 src/testdir/test_digraph.vim create mode 100644 src/testdir/test_display.vim create mode 100644 src/testdir/test_edit.vim create mode 100644 src/testdir/test_environ.vim create mode 100644 src/testdir/test_erasebackword.vim create mode 100644 src/testdir/test_escaped_glob.vim create mode 100644 src/testdir/test_eval_stuff.vim create mode 100644 src/testdir/test_ex_equal.vim create mode 100644 src/testdir/test_ex_mode.vim create mode 100644 src/testdir/test_ex_undo.vim create mode 100644 src/testdir/test_ex_z.vim create mode 100644 src/testdir/test_excmd.vim create mode 100644 src/testdir/test_exec_while_if.vim create mode 100644 src/testdir/test_execute_func.vim create mode 100644 src/testdir/test_exists.vim create mode 100644 src/testdir/test_exists_autocmd.vim create mode 100644 src/testdir/test_exit.vim create mode 100644 src/testdir/test_expand.vim create mode 100644 src/testdir/test_expand_dllpath.vim create mode 100644 src/testdir/test_expand_func.vim create mode 100644 src/testdir/test_expr.vim create mode 100644 src/testdir/test_expr_utf8.vim create mode 100644 src/testdir/test_file_perm.vim create mode 100644 src/testdir/test_file_size.vim create mode 100644 src/testdir/test_filechanged.vim create mode 100644 src/testdir/test_fileformat.vim create mode 100644 src/testdir/test_filetype.vim create mode 100644 src/testdir/test_filter_cmd.vim create mode 100644 src/testdir/test_filter_map.vim create mode 100644 src/testdir/test_find_complete.vim create mode 100644 src/testdir/test_findfile.vim create mode 100644 src/testdir/test_fixeol.vim create mode 100644 src/testdir/test_flatten.vim create mode 100644 src/testdir/test_float_func.vim create mode 100644 src/testdir/test_fnameescape.vim create mode 100644 src/testdir/test_fnamemodify.vim create mode 100644 src/testdir/test_fold.vim create mode 100644 src/testdir/test_function_lists.vim create mode 100644 src/testdir/test_functions.vim create mode 100644 src/testdir/test_ga.vim create mode 100644 src/testdir/test_getcwd.vim create mode 100644 src/testdir/test_getvar.vim create mode 100644 src/testdir/test_gf.vim create mode 100644 src/testdir/test_glob2regpat.vim create mode 100644 src/testdir/test_global.vim create mode 100644 src/testdir/test_gn.vim create mode 100644 src/testdir/test_goto.vim create mode 100644 src/testdir/test_gui.vim create mode 100644 src/testdir/test_gui_init.vim create mode 100644 src/testdir/test_hardcopy.vim create mode 100644 src/testdir/test_help.vim create mode 100644 src/testdir/test_help_tagjump.vim create mode 100644 src/testdir/test_hide.vim create mode 100644 src/testdir/test_highlight.vim create mode 100644 src/testdir/test_history.vim create mode 100644 src/testdir/test_hlsearch.vim create mode 100644 src/testdir/test_iminsert.vim create mode 100644 src/testdir/test_increment.vim create mode 100644 src/testdir/test_increment_dbcs.vim create mode 100644 src/testdir/test_indent.vim create mode 100644 src/testdir/test_input.vim create mode 100644 src/testdir/test_ins_complete.vim create mode 100644 src/testdir/test_ins_complete_no_halt.vim create mode 100644 src/testdir/test_interrupt.vim create mode 100644 src/testdir/test_job_fails.vim create mode 100644 src/testdir/test_join.vim create mode 100644 src/testdir/test_json.vim create mode 100644 src/testdir/test_jumplist.vim create mode 100644 src/testdir/test_lambda.vim create mode 100644 src/testdir/test_langmap.vim create mode 100644 src/testdir/test_largefile.vim create mode 100644 src/testdir/test_let.vim create mode 100644 src/testdir/test_lineending.vim create mode 100644 src/testdir/test_lispindent.vim create mode 100644 src/testdir/test_listchars.vim create mode 100644 src/testdir/test_listdict.vim create mode 100644 src/testdir/test_listener.vim create mode 100644 src/testdir/test_listlbr.vim create mode 100644 src/testdir/test_listlbr_utf8.vim create mode 100644 src/testdir/test_lua.vim create mode 100644 src/testdir/test_makeencoding.py create mode 100644 src/testdir/test_makeencoding.vim create mode 100644 src/testdir/test_man.vim create mode 100644 src/testdir/test_map_functions.vim create mode 100644 src/testdir/test_mapping.vim create mode 100644 src/testdir/test_marks.vim create mode 100644 src/testdir/test_match.vim create mode 100644 src/testdir/test_matchadd_conceal.vim create mode 100644 src/testdir/test_matchadd_conceal_utf8.vim create mode 100644 src/testdir/test_matchfuzzy.vim create mode 100644 src/testdir/test_memory_usage.vim create mode 100644 src/testdir/test_menu.vim create mode 100644 src/testdir/test_messages.vim create mode 100644 src/testdir/test_method.vim create mode 100644 src/testdir/test_mksession.vim create mode 100644 src/testdir/test_mksession_utf8.vim create mode 100644 src/testdir/test_modeless.vim create mode 100644 src/testdir/test_modeline.vim create mode 100644 src/testdir/test_move.vim create mode 100644 src/testdir/test_mswin_event.vim create mode 100644 src/testdir/test_mzscheme.vim create mode 100644 src/testdir/test_nested_function.vim create mode 100644 src/testdir/test_netbeans.py create mode 100644 src/testdir/test_netbeans.vim create mode 100644 src/testdir/test_normal.vim create mode 100644 src/testdir/test_number.vim create mode 100644 src/testdir/test_options.vim create mode 100644 src/testdir/test_packadd.vim create mode 100644 src/testdir/test_partial.vim create mode 100644 src/testdir/test_paste.vim create mode 100644 src/testdir/test_perl.vim create mode 100644 src/testdir/test_plus_arg_edit.vim create mode 100644 src/testdir/test_popup.vim create mode 100644 src/testdir/test_popupwin.vim create mode 100644 src/testdir/test_popupwin_textprop.vim create mode 100644 src/testdir/test_preview.vim create mode 100644 src/testdir/test_profile.vim create mode 100644 src/testdir/test_prompt_buffer.vim create mode 100644 src/testdir/test_put.vim create mode 100644 src/testdir/test_python2.vim create mode 100644 src/testdir/test_python3.vim create mode 100644 src/testdir/test_pyx2.vim create mode 100644 src/testdir/test_pyx3.vim create mode 100644 src/testdir/test_quickfix.vim create mode 100644 src/testdir/test_quotestar.vim create mode 100644 src/testdir/test_random.vim create mode 100644 src/testdir/test_recover.vim create mode 100644 src/testdir/test_regex_char_classes.vim create mode 100644 src/testdir/test_regexp_latin.vim create mode 100644 src/testdir/test_regexp_utf8.vim create mode 100644 src/testdir/test_registers.vim create mode 100644 src/testdir/test_reltime.vim create mode 100644 src/testdir/test_rename.vim create mode 100644 src/testdir/test_restricted.vim create mode 100644 src/testdir/test_retab.vim create mode 100644 src/testdir/test_ruby.vim create mode 100644 src/testdir/test_scriptnames.vim create mode 100644 src/testdir/test_scroll_opt.vim create mode 100644 src/testdir/test_scrollbind.vim create mode 100644 src/testdir/test_search.vim create mode 100644 src/testdir/test_search_stat.vim create mode 100644 src/testdir/test_searchpos.vim create mode 100644 src/testdir/test_selectmode.vim create mode 100644 src/testdir/test_set.vim create mode 100644 src/testdir/test_sha256.vim create mode 100644 src/testdir/test_shell.vim create mode 100644 src/testdir/test_shift.vim create mode 100644 src/testdir/test_short_sleep.py create mode 100644 src/testdir/test_shortpathname.vim create mode 100644 src/testdir/test_signals.vim create mode 100644 src/testdir/test_signs.vim create mode 100644 src/testdir/test_sleep.vim create mode 100644 src/testdir/test_smartindent.vim create mode 100644 src/testdir/test_sort.vim create mode 100644 src/testdir/test_sound.vim create mode 100644 src/testdir/test_source.vim create mode 100644 src/testdir/test_source_utf8.vim create mode 100644 src/testdir/test_spell.vim create mode 100644 src/testdir/test_spell_utf8.vim create mode 100644 src/testdir/test_spellfile.vim create mode 100644 src/testdir/test_startup.vim create mode 100644 src/testdir/test_startup_utf8.vim create mode 100644 src/testdir/test_stat.vim create mode 100644 src/testdir/test_statusline.vim create mode 100644 src/testdir/test_substitute.vim create mode 100644 src/testdir/test_suspend.vim create mode 100644 src/testdir/test_swap.vim create mode 100644 src/testdir/test_syn_attr.vim create mode 100644 src/testdir/test_syntax.vim create mode 100644 src/testdir/test_system.vim create mode 100644 src/testdir/test_tab.vim create mode 100644 src/testdir/test_tabline.vim create mode 100644 src/testdir/test_tabpage.vim create mode 100644 src/testdir/test_tagcase.vim create mode 100644 src/testdir/test_tagfunc.vim create mode 100644 src/testdir/test_tagjump.vim create mode 100644 src/testdir/test_taglist.vim create mode 100644 src/testdir/test_tcl.vim create mode 100644 src/testdir/test_termcodes.vim create mode 100644 src/testdir/test_termencoding.vim create mode 100644 src/testdir/test_terminal.vim create mode 100644 src/testdir/test_terminal2.vim create mode 100644 src/testdir/test_terminal3.vim create mode 100644 src/testdir/test_terminal_fail.vim create mode 100644 src/testdir/test_textformat.vim create mode 100644 src/testdir/test_textobjects.vim create mode 100644 src/testdir/test_textprop.vim create mode 100644 src/testdir/test_timers.vim create mode 100644 src/testdir/test_true_false.vim create mode 100644 src/testdir/test_trycatch.vim create mode 100644 src/testdir/test_undo.vim create mode 100644 src/testdir/test_unlet.vim create mode 100644 src/testdir/test_user_func.vim create mode 100644 src/testdir/test_usercommands.vim create mode 100644 src/testdir/test_utf8.vim create mode 100644 src/testdir/test_utf8_comparisons.vim create mode 100644 src/testdir/test_vartabs.vim create mode 100644 src/testdir/test_version.vim create mode 100644 src/testdir/test_vim9_assign.vim create mode 100644 src/testdir/test_vim9_builtin.vim create mode 100644 src/testdir/test_vim9_class.vim create mode 100644 src/testdir/test_vim9_cmd.vim create mode 100644 src/testdir/test_vim9_disassemble.vim create mode 100644 src/testdir/test_vim9_expr.vim create mode 100644 src/testdir/test_vim9_fails.vim create mode 100644 src/testdir/test_vim9_func.vim create mode 100644 src/testdir/test_vim9_import.vim create mode 100644 src/testdir/test_vim9_script.vim create mode 100644 src/testdir/test_viminfo.vim create mode 100644 src/testdir/test_vimscript.vim create mode 100644 src/testdir/test_virtualedit.vim create mode 100644 src/testdir/test_visual.vim create mode 100644 src/testdir/test_winbar.vim create mode 100644 src/testdir/test_winbuf_close.vim create mode 100644 src/testdir/test_window_cmd.vim create mode 100644 src/testdir/test_window_id.vim create mode 100644 src/testdir/test_windows_home.vim create mode 100644 src/testdir/test_wnext.vim create mode 100644 src/testdir/test_wordcount.vim create mode 100644 src/testdir/test_writefile.vim create mode 100644 src/testdir/test_xxd.vim create mode 100644 src/testdir/testluaplugin/lua/testluaplugin/hello.lua create mode 100644 src/testdir/testluaplugin/lua/testluaplugin/init.lua create mode 100644 src/testdir/thread_util.py create mode 100644 src/testdir/unix.vim create mode 100644 src/testdir/view_util.vim create mode 100644 src/testdir/vim9.vim create mode 100644 src/testdir/vms.vim create mode 100644 src/testing.c create mode 100644 src/textformat.c create mode 100644 src/textobject.c create mode 100644 src/textprop.c create mode 100644 src/time.c create mode 100644 src/toolbar.phi create mode 100755 src/toolcheck create mode 100644 src/tools.bmp create mode 100644 src/typemap create mode 100644 src/typval.c create mode 100644 src/ui.c create mode 100644 src/undo.c create mode 100644 src/uninstall.c create mode 100644 src/usercmd.c create mode 100644 src/userfunc.c create mode 100644 src/version.c create mode 100644 src/version.h create mode 100644 src/vim.h create mode 100644 src/vim.ico create mode 100644 src/vim.manifest create mode 100644 src/vim.rc create mode 100644 src/vim.tlb create mode 100644 src/vim9.h create mode 100644 src/vim9class.c create mode 100644 src/vim9cmds.c create mode 100644 src/vim9compile.c create mode 100644 src/vim9execute.c create mode 100644 src/vim9expr.c create mode 100644 src/vim9instr.c create mode 100644 src/vim9script.c create mode 100644 src/vim9type.c create mode 100644 src/vim_alert.ico create mode 100644 src/vim_error.ico create mode 100644 src/vim_icon.xbm create mode 100644 src/vim_info.ico create mode 100644 src/vim_mask.xbm create mode 100644 src/vim_quest.ico create mode 100644 src/viminfo.c create mode 100644 src/vimrun.c create mode 100755 src/vimtutor create mode 100755 src/which.sh create mode 100644 src/winclip.c create mode 100644 src/window.c create mode 100644 src/xdiff/COPYING create mode 100644 src/xdiff/README.txt create mode 100644 src/xdiff/xdiff.h create mode 100644 src/xdiff/xdiffi.c create mode 100644 src/xdiff/xdiffi.h create mode 100644 src/xdiff/xemit.c create mode 100644 src/xdiff/xemit.h create mode 100644 src/xdiff/xhistogram.c create mode 100644 src/xdiff/xinclude.h create mode 100644 src/xdiff/xmacros.h create mode 100644 src/xdiff/xpatience.c create mode 100644 src/xdiff/xprepare.c create mode 100644 src/xdiff/xprepare.h create mode 100644 src/xdiff/xtypes.h create mode 100644 src/xdiff/xutils.c create mode 100644 src/xdiff/xutils.h create mode 100644 src/xpm/COPYRIGHT create mode 100644 src/xpm/README.txt create mode 100644 src/xpm/arm64/lib-vc14/libXpm.lib create mode 100644 src/xpm/include/simx.h create mode 100644 src/xpm/include/xpm.h create mode 100644 src/xpm/x64/lib-vc14/libXpm.lib create mode 100644 src/xpm/x64/lib/libXpm.a create mode 100644 src/xpm/x86/lib-vc14/libXpm.lib create mode 100644 src/xpm/x86/lib/libXpm.a create mode 100644 src/xpm_w32.c create mode 100644 src/xpm_w32.h create mode 100644 src/xxd/Make_amiga.mak create mode 100644 src/xxd/Make_ming.mak create mode 100644 src/xxd/Make_mvc.mak create mode 100644 src/xxd/Make_vms.mms create mode 100644 src/xxd/Makefile create mode 100644 src/xxd/xxd.c (limited to 'src') diff --git a/src/GvimExt/GvimExt.reg b/src/GvimExt/GvimExt.reg new file mode 100644 index 0000000..d9ebff8 --- /dev/null +++ b/src/GvimExt/GvimExt.reg @@ -0,0 +1,20 @@ +REGEDIT4 + +[HKEY_CLASSES_ROOT\CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}] + @="Vim Shell Extension" +[HKEY_CLASSES_ROOT\CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\InProcServer32] + @="gvimext.dll" + "ThreadingModel"="Apartment" + +[HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\gvim] + @="{51EEE242-AD87-11d3-9C1E-0090278BBD99}" + +[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved] + "{51EEE242-AD87-11d3-9C1E-0090278BBD99}"="Vim Shell Extension" + +[HKEY_LOCAL_MACHINE\Software\Vim\Gvim] + "path"="gvim.exe" + +[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\Vim 9.0] + "DisplayName"="Vim 9.0: Edit with Vim popup menu entry" + "UninstallString"="uninstall.exe" diff --git a/src/GvimExt/Make_ming.mak b/src/GvimExt/Make_ming.mak new file mode 100644 index 0000000..0ebe08a --- /dev/null +++ b/src/GvimExt/Make_ming.mak @@ -0,0 +1,83 @@ +# Project: gvimext +# Generates gvimext.dll with gcc. +# To be used with MingW and Cygwin. +# +# Originally, the DLL base address was fixed: -Wl,--image-base=0x1C000000 +# Now it is allocated dynamically by the linker by evaluating all DLLs +# already loaded in memory. The binary image contains as well information +# for automatic pseudo-rebasing, if needed by the system. ALV 2004-02-29 + +# If cross-compiling set this to yes, else set it to no +CROSS = no +#CROSS = yes +# For the old MinGW 2.95 (the one you get e.g. with debian woody) +# set the following variable to yes and check if the executables are +# really named that way. +# If you have a newer MinGW or you are using cygwin set it to no and +# check also the executables +MINGWOLD = no + +# Link against the shared versions of libgcc/libstdc++ by default. Set +# STATIC_STDCPLUS to "yes" to link against static versions instead. +STATIC_STDCPLUS=no +#STATIC_STDCPLUS=yes + +# Note: -static-libstdc++ is not available until gcc 4.5.x. +LDFLAGS += -shared +ifeq (yes, $(STATIC_STDCPLUS)) +LDFLAGS += -static-libgcc -static-libstdc++ +endif + +ifeq ($(CROSS),yes) +DEL = rm +ifeq ($(MINGWOLD),yes) +CXXFLAGS := -O2 -fvtable-thunks +else +CXXFLAGS := -O2 +endif +else +CXXFLAGS := -O2 +ifneq (sh.exe, $(SHELL)) +DEL = rm +else +DEL = del +endif +endif +# Set the default $(WINVER) to make it work with WinXP. +ifndef WINVER +WINVER = 0x0501 +endif +CXX := $(CROSS_COMPILE)g++ +WINDRES := $(CROSS_COMPILE)windres +# this used to have --preprocessor, but it's no longer supported +WINDRES_FLAGS = +LIBS := -luuid -lgdi32 +RES := gvimext.res +ifeq ($(findstring clang++,$(CXX)),) +DEFFILE = gvimext_ming.def +endif +OBJ := gvimext.o + +DLL := gvimext.dll + +.PHONY: all all-before all-after clean clean-custom + +all: all-before $(DLL) all-after + +$(DLL): $(OBJ) $(RES) $(DEFFILE) + $(CXX) $(LDFLAGS) $(CXXFLAGS) -s -o $@ \ + -Wl,--enable-auto-image-base \ + -Wl,--enable-auto-import \ + -Wl,--whole-archive \ + $^ \ + -Wl,--no-whole-archive \ + $(LIBS) + +gvimext.o: gvimext.cpp + $(CXX) $(CXXFLAGS) -DFEAT_GETTEXT -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER) -c $? -o $@ + +$(RES): gvimext_ming.rc + $(WINDRES) $(WINDRES_FLAGS) --input-format=rc --output-format=coff -DMING $? -o $@ + +clean: clean-custom + -$(DEL) $(OBJ) $(RES) $(DLL) diff --git a/src/GvimExt/Make_mvc.mak b/src/GvimExt/Make_mvc.mak new file mode 100644 index 0000000..4b83f52 --- /dev/null +++ b/src/GvimExt/Make_mvc.mak @@ -0,0 +1,98 @@ +# Makefile for GvimExt, using MSVC +# Options: +# DEBUG=yes Build debug version (for VC7 and maybe later) +# CPUARG= /arch:IA32/AVX/etc, call from main makefile to set +# automatically from CPUNR +# + +TARGETOS = WINNT + +!ifndef APPVER +APPVER = 5.01 +!endif +!ifndef WINVER +WINVER = 0x0501 +!endif + +!if "$(DEBUG)" != "yes" +NODEBUG = 1 +!endif + +!ifdef PROCESSOR_ARCHITECTURE +# On Windows NT +! ifndef CPU +CPU = i386 +! if !defined(PLATFORM) && defined(TARGET_CPU) +PLATFORM = $(TARGET_CPU) +! endif +! ifdef PLATFORM +! if ("$(PLATFORM)" == "x64") || ("$(PLATFORM)" == "X64") +CPU = AMD64 +! elseif ("$(PLATFORM)" == "arm64") || ("$(PLATFORM)" == "ARM64") +CPU = ARM64 +! elseif ("$(PLATFORM)" != "x86") && ("$(PLATFORM)" != "X86") +! error *** ERROR Unknown target platform "$(PLATFORM)". Make aborted. +! endif +! endif +! endif +!else +CPU = i386 +!endif + +!ifdef SDK_INCLUDE_DIR +!include $(SDK_INCLUDE_DIR)\Win32.mak +!elseif "$(USE_WIN32MAK)"=="yes" +!include +!else +cc = cl +link = link +rc = rc +cflags = -nologo -c +lflags = -incremental:no -nologo +rcflags = /r +olelibsdll = ole32.lib uuid.lib oleaut32.lib user32.lib gdi32.lib advapi32.lib +!endif + +# include CPUARG +cflags = $(cflags) $(CPUARG) + +# set WINVER and _WIN32_WINNT +cflags = $(cflags) -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER) + +!if "$(CL)" == "/D_USING_V110_SDK71_" +rcflags = $(rcflags) /D_USING_V110_SDK71_ +!endif + +SUBSYSTEM = console +!if "$(SUBSYSTEM_VER)" != "" +SUBSYSTEM = $(SUBSYSTEM),$(SUBSYSTEM_VER) +!endif + +!if "$(CPU)" == "AMD64" || "$(CPU)" == "ARM64" +OFFSET = 0x11C000000 +!else +OFFSET = 0x1C000000 +!endif + +all: gvimext.dll + +gvimext.dll: gvimext.obj \ + gvimext.res + $(link) $(lflags) -dll -def:gvimext.def -base:$(OFFSET) -out:$*.dll $** $(olelibsdll) shell32.lib comctl32.lib -subsystem:$(SUBSYSTEM) + if exist $*.dll.manifest mt -nologo -manifest $*.dll.manifest -outputresource:$*.dll;2 + +gvimext.obj: gvimext.h + +.cpp.obj: + $(cc) $(cflags) -DFEAT_GETTEXT $(cvarsmt) $*.cpp + +gvimext.res: gvimext.rc + $(rc) /nologo $(rcflags) $(rcvars) gvimext.rc + +clean: + - if exist gvimext.dll del gvimext.dll + - if exist gvimext.lib del gvimext.lib + - if exist gvimext.exp del gvimext.exp + - if exist gvimext.obj del gvimext.obj + - if exist gvimext.res del gvimext.res + - if exist gvimext.dll.manifest del gvimext.dll.manifest diff --git a/src/GvimExt/Makefile b/src/GvimExt/Makefile new file mode 100644 index 0000000..18b91ec --- /dev/null +++ b/src/GvimExt/Makefile @@ -0,0 +1,4 @@ +!message This makefile is deprecated. Use Make_mvc.mak instead. +!message + +!include Make_mvc.mak diff --git a/src/GvimExt/README.txt b/src/GvimExt/README.txt new file mode 100644 index 0000000..a29200e --- /dev/null +++ b/src/GvimExt/README.txt @@ -0,0 +1,94 @@ +README.txt for the gvimext DLL. + +Written by Tianmiao Hu. Edited by Bram Moolenaar. + + +INSTALLATION + +To install the "Edit with Vim" popup menu entry, it is recommended to use the +"install.exe" program. It will ask you a few questions and install the needed +registry entries. + +In special situations you might want to make changes by hand. Check these +items: +- The gvimext.dll, gvim.exe and uninstall.exe either need to be in the search + path, or you have to set the full path in the registry entries. You could + move the gvimext.dll to the "windows\system" or "windows\system32" + directory, where the other DLL files are. +- You can find the names of the used registry entries in the file + "GvimExt.reg". You can edit this file to add the paths. To install the + registry entries, right-click the gvimext.reg file and choose the "merge" + menu option. +- The registry key [HKEY_LOCAL_MACHINE\Software\Vim\Gvim] is used by the + gvimext.dll. The value "path" specifies the location of "gvim.exe". If + gvim.exe is in the search path, the path can be omitted. The value "lang" + can be used to set the language, for example "de" for German. If "lang" is + omitted, the language set for Windows will be used. + +It is the preferred method to keep gvim.exe with the runtime files, so that +Vim will find them (also the translated menu items are there). + + +UNINSTALLATION + +To uninstall the "Edit with Vim" popup menu entry, it is recommended to use +the "uninstal.exe" program. + +In special situations you might want to uninstall by hand: +- Open the registry by running regedit.exe. +- Delete all the keys listed in GvimExt.reg, except this one: + [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved] + For this key, only delete one value: + "{51EEE242-AD87-11d3-9C1E-0090278BBD99}"="Vim Shell Extension" +- Delete the gvimext.dll, if you want. You might need to reboot the machine + in order to remove this file. A quick way is to log off and re-login. + +Another method is by using the uninst.bat script: + uninst gvimext.inf +This batch file will remove all the registry keys from the system. Then you +can remove the gvimext.dll file. +Note: In order for this batch file to work, you must have two system files: +rundll32.exe and setupapi.dll. I believe you will have rundll32.exe in your +system. I know windows nt 4.0 with the service pack 4 has setupapi.dll. My +windows 95 has setupapi.dll. I find that the internet explorer 4.0 comes with +the setupapi.dll in file Ie4_5.cab. + +If you do encounter problems running this script, then probably you need to +modify the uninst.bat to suit to your system. Basically, you must find out +where are the locations for your rundll32.exe and setupapi.dll files. In +windows nt, both files are under c:\winnt\system32 directory. In my windows 95 +system, I got setupapi.dll at c:\windows\system and rundll32.exe at +c:\windows. So you might want to try something like: + rundll32.exe c:\windows\system\setupapi.dll,InstallHinfSection DefaultUninstall 128 %1 +where %1 can be substituted by gvimext.inf + + +THE SOURCE CODE + +I have provided the source code here in hope that gvim users around world can +further enhance this little dll. I believe the only thing you need to change +is gvimext.cpp file. The important two functions you need to look at are +QueryContextMenu and InvokeCommand. You can modify right-click menus in the +QueryContextMenu function and invoke gvim in the InvokeCommand function. Note +the selected files can be accessed from the DragQueryFile function. I am not +familiar with the invoking options for gvim. I believe there are some +improvements that can be made on that side. + +I use MS Visual C++ 6.0's nmake to make the gvimext.dll. I don't have a +chance to try earlier versions of MSVC. The files that are required for build +are: + gvimext.cpp + gvimext.h + gvimext.def + gvimext.rc + resource.h + Makefile + +To compile the DLL from the command line: + vcvars32 + nmake -f Makefile + +If you did something interesting to this dll, please let me know +@ tianmiao@acm.org. + +Happy vimming!!! diff --git a/src/GvimExt/gvimext.cpp b/src/GvimExt/gvimext.cpp new file mode 100644 index 0000000..dd26eb1 --- /dev/null +++ b/src/GvimExt/gvimext.cpp @@ -0,0 +1,970 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved gvimext by Tianmiao Hu + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * gvimext is a DLL which is used for the "Edit with Vim" context menu + * extension. It implements a MS defined interface with the Shell. + * + * If you have any questions or any suggestions concerning gvimext, please + * contact Tianmiao Hu: tianmiao@acm.org. + */ + +#include "gvimext.h" + +static char *searchpath(char *name); + +// Always get an error while putting the following stuff to the +// gvimext.h file as class protected variables, give up and +// declare them as global stuff +FORMATETC fmte = {CF_HDROP, + (DVTARGETDEVICE FAR *)NULL, + DVASPECT_CONTENT, + -1, + TYMED_HGLOBAL + }; +STGMEDIUM medium; +HRESULT hres = 0; +UINT cbFiles = 0; + +/* The buffers size used to be MAX_PATH (260 bytes), but that's not always + * enough */ +#define BUFSIZE 1100 + +// The "Edit with Vim" shell extension provides these choices when +// a new instance of Gvim is selected: +// - use tabpages +// - enable diff mode +// - none of the above +#define EDIT_WITH_VIM_USE_TABPAGES (2) +#define EDIT_WITH_VIM_IN_DIFF_MODE (1) +#define EDIT_WITH_VIM_NO_OPTIONS (0) + +// +// Get the name of the Gvim executable to use, with the path. +// When "runtime" is non-zero, we were called to find the runtime directory. +// Returns the path in name[BUFSIZE]. It's empty when it fails. +// + static void +getGvimName(char *name, int runtime) +{ + HKEY keyhandle; + DWORD hlen; + + // Get the location of gvim from the registry. + name[0] = 0; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0, + KEY_READ, &keyhandle) == ERROR_SUCCESS) + { + hlen = BUFSIZE; + if (RegQueryValueEx(keyhandle, "path", 0, NULL, (BYTE *)name, &hlen) + != ERROR_SUCCESS) + name[0] = 0; + else + name[hlen] = 0; + RegCloseKey(keyhandle); + } + + // Registry didn't work, use the search path. + if (name[0] == 0) + strcpy(name, searchpath((char *)"gvim.exe")); + + if (!runtime) + { + // Only when looking for the executable, not the runtime dir, we can + // search for the batch file or a name without a path. + if (name[0] == 0) + strcpy(name, searchpath((char *)"gvim.bat")); + if (name[0] == 0) + strcpy(name, "gvim"); // finds gvim.bat or gvim.exe + } +} + + static void +getGvimInvocation(char *name, int runtime) +{ + getGvimName(name, runtime); + // avoid that Vim tries to expand wildcards in the file names + strcat(name, " --literal"); +} + + static void +getGvimInvocationW(wchar_t *nameW) +{ + char *name; + + name = (char *)malloc(BUFSIZE); + getGvimInvocation(name, 0); + mbstowcs(nameW, name, BUFSIZE); + free(name); +} + +// +// Get the Vim runtime directory into buf[BUFSIZE]. +// The result is empty when it failed. +// When it works, the path ends in a slash or backslash. +// + static void +getRuntimeDir(char *buf) +{ + int idx; + + getGvimName(buf, 1); + if (buf[0] != 0) + { + // When no path found, use the search path to expand it. + if (strchr(buf, '/') == NULL && strchr(buf, '\\') == NULL) + strcpy(buf, searchpath(buf)); + + // remove "gvim.exe" from the end + for (idx = (int)strlen(buf) - 1; idx >= 0; idx--) + if (buf[idx] == '\\' || buf[idx] == '/') + { + buf[idx + 1] = 0; + break; + } + } +} + +HBITMAP IconToBitmap(HICON hIcon, HBRUSH hBackground, int width, int height) +{ + HDC hDC = GetDC(NULL); + HDC hMemDC = CreateCompatibleDC(hDC); + HBITMAP hMemBmp = CreateCompatibleBitmap(hDC, width, height); + HBITMAP hResultBmp = NULL; + HGDIOBJ hOrgBMP = SelectObject(hMemDC, hMemBmp); + + DrawIconEx(hMemDC, 0, 0, hIcon, width, height, 0, hBackground, DI_NORMAL); + + hResultBmp = hMemBmp; + hMemBmp = NULL; + + SelectObject(hMemDC, hOrgBMP); + DeleteDC(hMemDC); + ReleaseDC(NULL, hDC); + DestroyIcon(hIcon); + return hResultBmp; +} + +// +// GETTEXT: translated messages and menu entries +// +#ifndef FEAT_GETTEXT +# define _(x) x +#else +# define _(x) (*dyn_libintl_gettext)(x) +# define VIMPACKAGE "vim" +# ifndef GETTEXT_DLL +# define GETTEXT_DLL "libintl.dll" +# define GETTEXT_DLL_ALT "libintl-8.dll" +# endif + +// Dummy functions +static char *null_libintl_gettext(const char *); +static char *null_libintl_textdomain(const char *); +static char *null_libintl_bindtextdomain(const char *, const char *); +static int dyn_libintl_init(char *dir); +static void dyn_libintl_end(void); + +static HINSTANCE hLibintlDLL = 0; +static char *(*dyn_libintl_gettext)(const char *) = null_libintl_gettext; +static char *(*dyn_libintl_textdomain)(const char *) = null_libintl_textdomain; +static char *(*dyn_libintl_bindtextdomain)(const char *, const char *) + = null_libintl_bindtextdomain; + +// +// Attempt to load libintl.dll. If it doesn't work, use dummy functions. +// "dir" is the directory where the libintl.dll might be. +// Return 1 for success, 0 for failure. +// + static int +dyn_libintl_init(char *dir) +{ + int i; + static struct + { + char *name; + FARPROC *ptr; + } libintl_entry[] = + { + {(char *)"gettext", (FARPROC*)&dyn_libintl_gettext}, + {(char *)"textdomain", (FARPROC*)&dyn_libintl_textdomain}, + {(char *)"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain}, + {NULL, NULL} + }; + DWORD len, len2; + LPWSTR buf = NULL; + LPWSTR buf2 = NULL; + + // No need to initialize twice. + if (hLibintlDLL) + return 1; + + // Load gettext library from $VIMRUNTIME\GvimExt{64,32} directory. + // Add the directory to $PATH temporarily. + len = GetEnvironmentVariableW(L"PATH", NULL, 0); + len2 = MAX_PATH + 1 + len; + buf = (LPWSTR)malloc(len * sizeof(WCHAR)); + buf2 = (LPWSTR)malloc(len2 * sizeof(WCHAR)); + if (buf != NULL && buf2 != NULL) + { + GetEnvironmentVariableW(L"PATH", buf, len); +# ifdef _WIN64 + _snwprintf(buf2, len2, L"%S\\GvimExt64;%s", dir, buf); +# else + _snwprintf(buf2, len2, L"%S\\GvimExt32;%s", dir, buf); +# endif + SetEnvironmentVariableW(L"PATH", buf2); + hLibintlDLL = LoadLibrary(GETTEXT_DLL); +# ifdef GETTEXT_DLL_ALT + if (!hLibintlDLL) + hLibintlDLL = LoadLibrary(GETTEXT_DLL_ALT); +# endif + SetEnvironmentVariableW(L"PATH", buf); + } + free(buf); + free(buf2); + if (!hLibintlDLL) + return 0; + + // Get the addresses of the functions we need. + for (i = 0; libintl_entry[i].name != NULL + && libintl_entry[i].ptr != NULL; ++i) + { + if ((*libintl_entry[i].ptr = GetProcAddress(hLibintlDLL, + libintl_entry[i].name)) == NULL) + { + dyn_libintl_end(); + return 0; + } + } + return 1; +} + + static void +dyn_libintl_end(void) +{ + if (hLibintlDLL) + FreeLibrary(hLibintlDLL); + hLibintlDLL = NULL; + dyn_libintl_gettext = null_libintl_gettext; + dyn_libintl_textdomain = null_libintl_textdomain; + dyn_libintl_bindtextdomain = null_libintl_bindtextdomain; +} + + static char * +null_libintl_gettext(const char *msgid) +{ + return (char *)msgid; +} + + static char * +null_libintl_bindtextdomain(const char * /* domainname */, const char * /* dirname */) +{ + return NULL; +} + + static char * +null_libintl_textdomain(const char* /* domainname */) +{ + return NULL; +} + +// +// Setup for translating strings. +// + static void +dyn_gettext_load(void) +{ + char szBuff[BUFSIZE]; + DWORD len; + + // Try to locate the runtime files. The path is used to find libintl.dll + // and the vim.mo files. + getRuntimeDir(szBuff); + if (szBuff[0] != 0) + { + len = (DWORD)strlen(szBuff); + if (dyn_libintl_init(szBuff)) + { + strcpy(szBuff + len, "lang"); + + (*dyn_libintl_bindtextdomain)(VIMPACKAGE, szBuff); + (*dyn_libintl_textdomain)(VIMPACKAGE); + } + } +} + + static void +dyn_gettext_free(void) +{ + dyn_libintl_end(); +} +#endif // FEAT_GETTEXT + +// +// Global variables +// +UINT g_cRefThisDll = 0; // Reference count of this DLL. +HINSTANCE g_hmodThisDll = NULL; // Handle to this DLL itself. + + +//--------------------------------------------------------------------------- +// DllMain +//--------------------------------------------------------------------------- +extern "C" int APIENTRY +DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReserved */) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + // Extension DLL one-time initialization + g_hmodThisDll = hInstance; + break; + + case DLL_PROCESS_DETACH: + break; + } + + return 1; // ok +} + + static void +inc_cRefThisDLL() +{ +#ifdef FEAT_GETTEXT + if (g_cRefThisDll == 0) + dyn_gettext_load(); +#endif + InterlockedIncrement((LPLONG)&g_cRefThisDll); +} + + static void +dec_cRefThisDLL() +{ +#ifdef FEAT_GETTEXT + if (InterlockedDecrement((LPLONG)&g_cRefThisDll) == 0) + dyn_gettext_free(); +#else + InterlockedDecrement((LPLONG)&g_cRefThisDll); +#endif +} + +//--------------------------------------------------------------------------- +// DllCanUnloadNow +//--------------------------------------------------------------------------- + +STDAPI DllCanUnloadNow(void) +{ + return (g_cRefThisDll == 0 ? S_OK : S_FALSE); +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut) +{ + *ppvOut = NULL; + + if (IsEqualIID(rclsid, CLSID_ShellExtension)) + { + CShellExtClassFactory *pcf = new CShellExtClassFactory; + + return pcf->QueryInterface(riid, ppvOut); + } + + return CLASS_E_CLASSNOTAVAILABLE; +} + +CShellExtClassFactory::CShellExtClassFactory() +{ + m_cRef = 0L; + + inc_cRefThisDLL(); +} + +CShellExtClassFactory::~CShellExtClassFactory() +{ + dec_cRefThisDLL(); +} + +STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID riid, + LPVOID FAR *ppv) +{ + *ppv = NULL; + + // any interface on this object is the object pointer + + if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) + { + *ppv = (LPCLASSFACTORY)this; + + AddRef(); + + return NOERROR; + } + + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef() +{ + return InterlockedIncrement((LPLONG)&m_cRef); +} + +STDMETHODIMP_(ULONG) CShellExtClassFactory::Release() +{ + if (InterlockedDecrement((LPLONG)&m_cRef)) + return m_cRef; + + delete this; + + return 0L; +} + +STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, + REFIID riid, + LPVOID *ppvObj) +{ + *ppvObj = NULL; + + // Shell extensions typically don't support aggregation (inheritance) + + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + // Create the main shell extension object. The shell will then call + // QueryInterface with IID_IShellExtInit--this is how shell extensions are + // initialized. + + LPCSHELLEXT pShellExt = new CShellExt(); // create the CShellExt object + + if (NULL == pShellExt) + return E_OUTOFMEMORY; + + return pShellExt->QueryInterface(riid, ppvObj); +} + + +STDMETHODIMP CShellExtClassFactory::LockServer(BOOL /* fLock */) +{ + return NOERROR; +} + +// *********************** CShellExt ************************* +CShellExt::CShellExt() +{ + m_cRef = 0L; + m_pDataObj = NULL; + + inc_cRefThisDLL(); + + LoadMenuIcon(); +} + +CShellExt::~CShellExt() +{ + if (m_pDataObj) + m_pDataObj->Release(); + + dec_cRefThisDLL(); + + if (m_hVimIconBitmap) + DeleteObject(m_hVimIconBitmap); +} + +STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv) +{ + *ppv = NULL; + + if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) + { + *ppv = (LPSHELLEXTINIT)this; + } + else if (IsEqualIID(riid, IID_IContextMenu)) + { + *ppv = (LPCONTEXTMENU)this; + } + + if (*ppv) + { + AddRef(); + + return NOERROR; + } + + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) CShellExt::AddRef() +{ + return InterlockedIncrement((LPLONG)&m_cRef); +} + +STDMETHODIMP_(ULONG) CShellExt::Release() +{ + + if (InterlockedDecrement((LPLONG)&m_cRef)) + return m_cRef; + + delete this; + + return 0L; +} + + +// +// FUNCTION: CShellExt::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY) +// +// PURPOSE: Called by the shell when initializing a context menu or property +// sheet extension. +// +// PARAMETERS: +// pIDFolder - Specifies the parent folder +// pDataObj - Specifies the set of items selected in that folder. +// hRegKey - Specifies the type of the focused item in the selection. +// +// RETURN VALUE: +// +// NOERROR in all cases. +// +// COMMENTS: Note that at the time this function is called, we don't know +// (or care) what type of shell extension is being initialized. +// It could be a context menu or a property sheet. +// + +STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST /* pIDFolder */, + LPDATAOBJECT pDataObj, + HKEY /* hRegKey */) +{ + // Initialize can be called more than once + if (m_pDataObj) + m_pDataObj->Release(); + + // duplicate the object pointer and registry handle + + if (pDataObj) + { + m_pDataObj = pDataObj; + pDataObj->AddRef(); + } + + return NOERROR; +} + + +// +// FUNCTION: CShellExt::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT) +// +// PURPOSE: Called by the shell just before the context menu is displayed. +// This is where you add your specific menu items. +// +// PARAMETERS: +// hMenu - Handle to the context menu +// indexMenu - Index of where to begin inserting menu items +// idCmdFirst - Lowest value for new menu ID's +// idCmtLast - Highest value for new menu ID's +// uFlags - Specifies the context of the menu event +// +// RETURN VALUE: +// +// +// COMMENTS: +// + +STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, + UINT indexMenu, + UINT idCmdFirst, + UINT /* idCmdLast */, + UINT /* uFlags */) +{ + UINT idCmd = idCmdFirst; + + hres = m_pDataObj->GetData(&fmte, &medium); + if (medium.hGlobal) + cbFiles = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, 0, 0); + + // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); + + // Initialize m_cntOfHWnd to 0 + m_cntOfHWnd = 0; + + HKEY keyhandle; + bool showExisting = true; + bool showIcons = true; + + // Check whether "Edit with existing Vim" entries are disabled. + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0, + KEY_READ, &keyhandle) == ERROR_SUCCESS) + { + if (RegQueryValueEx(keyhandle, "DisableEditWithExisting", 0, NULL, + NULL, NULL) == ERROR_SUCCESS) + showExisting = false; + if (RegQueryValueEx(keyhandle, "DisableContextMenuIcons", 0, NULL, + NULL, NULL) == ERROR_SUCCESS) + showIcons = false; + RegCloseKey(keyhandle); + } + + // Retrieve all the vim instances, unless disabled. + if (showExisting) + EnumWindows(EnumWindowsProc, (LPARAM)this); + + MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; + mii.fMask = MIIM_STRING | MIIM_ID; + if (showIcons) + { + mii.fMask |= MIIM_BITMAP; + mii.hbmpItem = m_hVimIconBitmap; + } + + if (cbFiles > 1) + { + mii.wID = idCmd++; + mii.dwTypeData = _("Edit with Vim using &tabpages"); + mii.cch = lstrlen(mii.dwTypeData); + InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); + + mii.wID = idCmd++; + mii.dwTypeData = _("Edit with single &Vim"); + mii.cch = lstrlen(mii.dwTypeData); + InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); + + if (cbFiles <= 4) + { + // Can edit up to 4 files in diff mode + mii.wID = idCmd++; + mii.dwTypeData = _("Diff with Vim"); + mii.cch = lstrlen(mii.dwTypeData); + InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); + m_edit_existing_off = 3; + } + else + m_edit_existing_off = 2; + + } + else + { + mii.wID = idCmd++; + mii.dwTypeData = _("Edit with &Vim"); + mii.cch = lstrlen(mii.dwTypeData); + InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); + m_edit_existing_off = 1; + } + + HMENU hSubMenu = NULL; + if (m_cntOfHWnd > 1) + { + hSubMenu = CreatePopupMenu(); + mii.fMask |= MIIM_SUBMENU; + mii.wID = idCmd; + mii.dwTypeData = _("Edit with existing Vim"); + mii.cch = lstrlen(mii.dwTypeData); + mii.hSubMenu = hSubMenu; + InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); + mii.fMask = mii.fMask & ~MIIM_SUBMENU; + mii.hSubMenu = NULL; + } + // Now display all the vim instances + for (int i = 0; i < m_cntOfHWnd; i++) + { + char title[BUFSIZE]; + char temp[BUFSIZE]; + int index; + HMENU hmenu; + + // Obtain window title, continue if can not + if (GetWindowText(m_hWnd[i], title, BUFSIZE - 1) == 0) + continue; + // Truncate the title before the path, keep the file name + char *pos = strchr(title, '('); + if (pos != NULL) + { + if (pos > title && pos[-1] == ' ') + --pos; + *pos = 0; + } + // Now concatenate + if (m_cntOfHWnd > 1) + temp[0] = '\0'; + else + { + strncpy(temp, _("Edit with existing Vim - "), BUFSIZE - 1); + temp[BUFSIZE - 1] = '\0'; + } + strncat(temp, title, BUFSIZE - 1 - strlen(temp)); + temp[BUFSIZE - 1] = '\0'; + + mii.wID = idCmd++; + mii.dwTypeData = temp; + mii.cch = lstrlen(mii.dwTypeData); + if (m_cntOfHWnd > 1) + { + hmenu = hSubMenu; + index = i; + } + else + { + hmenu = hMenu; + index = indexMenu++; + } + InsertMenuItem(hmenu, index, TRUE, &mii); + } + // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); + + // Must return number of menu items we added. + return ResultFromShort(idCmd-idCmdFirst); +} + +// +// FUNCTION: CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO) +// +// PURPOSE: Called by the shell after the user has selected on of the +// menu items that was added in QueryContextMenu(). +// +// PARAMETERS: +// lpcmi - Pointer to an CMINVOKECOMMANDINFO structure +// +// RETURN VALUE: +// +// +// COMMENTS: +// + +STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) +{ + HRESULT hr = E_INVALIDARG; + int gvimExtraOptions; + + // If HIWORD(lpcmi->lpVerb) then we have been called programmatically + // and lpVerb is a command that should be invoked. Otherwise, the shell + // has called us, and LOWORD(lpcmi->lpVerb) is the menu ID the user has + // selected. Actually, it's (menu ID - idCmdFirst) from QueryContextMenu(). + if (!HIWORD(lpcmi->lpVerb)) + { + UINT idCmd = LOWORD(lpcmi->lpVerb); + + if (idCmd >= m_edit_existing_off) + { + // Existing with vim instance + hr = PushToWindow(lpcmi->hwnd, + lpcmi->lpDirectory, + lpcmi->lpVerb, + lpcmi->lpParameters, + lpcmi->nShow, + idCmd - m_edit_existing_off); + } + else + { + switch (idCmd) + { + case 0: + gvimExtraOptions = EDIT_WITH_VIM_USE_TABPAGES; + break; + case 1: + gvimExtraOptions = EDIT_WITH_VIM_NO_OPTIONS; + break; + case 2: + gvimExtraOptions = EDIT_WITH_VIM_IN_DIFF_MODE; + break; + default: + // If execution reaches this point we likely have an + // inconsistency between the code that setup the menus + // and this code that determines what the user + // selected. This should be detected and fixed during + // development. + return E_FAIL; + } + + LPCMINVOKECOMMANDINFOEX lpcmiex = (LPCMINVOKECOMMANDINFOEX)lpcmi; + LPCWSTR currentDirectory = lpcmi->cbSize == sizeof(CMINVOKECOMMANDINFOEX) ? lpcmiex->lpDirectoryW : NULL; + + hr = InvokeSingleGvim(lpcmi->hwnd, + currentDirectory, + lpcmi->lpVerb, + lpcmi->lpParameters, + lpcmi->nShow, + gvimExtraOptions); + } + } + return hr; +} + +STDMETHODIMP CShellExt::PushToWindow(HWND /* hParent */, + LPCSTR /* pszWorkingDir */, + LPCSTR /* pszCmd */, + LPCSTR /* pszParam */, + int /* iShowCmd */, + int idHWnd) +{ + HWND hWnd = m_hWnd[idHWnd]; + + // Show and bring vim instance to foreground + if (IsIconic(hWnd) != 0) + ShowWindow(hWnd, SW_RESTORE); + else + ShowWindow(hWnd, SW_SHOW); + SetForegroundWindow(hWnd); + + // Post the selected files to the vim instance + PostMessage(hWnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0); + + return NOERROR; +} + +STDMETHODIMP CShellExt::GetCommandString(UINT_PTR /* idCmd */, + UINT uFlags, + UINT FAR * /* reserved */, + LPSTR pszName, + UINT cchMax) +{ + if (uFlags == GCS_HELPTEXT && cchMax > 35) + lstrcpy(pszName, _("Edits the selected file(s) with Vim")); + + return NOERROR; +} + +BOOL CALLBACK CShellExt::EnumWindowsProc(HWND hWnd, LPARAM lParam) +{ + char temp[BUFSIZE]; + + // First do a bunch of check + // No invisible window + if (!IsWindowVisible(hWnd)) return TRUE; + // No child window ??? + // if (GetParent(hWnd)) return TRUE; + // Class name should be Vim, if failed to get class name, return + if (GetClassName(hWnd, temp, sizeof(temp)) == 0) + return TRUE; + // Compare class name to that of vim, if not, return + if (_strnicmp(temp, "vim", sizeof("vim")) != 0) + return TRUE; + // First check if the number of vim instance exceeds MAX_HWND + CShellExt *cs = (CShellExt*) lParam; + if (cs->m_cntOfHWnd >= MAX_HWND) return TRUE; + // Now we get the vim window, put it into some kind of array + cs->m_hWnd[cs->m_cntOfHWnd] = hWnd; + cs->m_cntOfHWnd ++; + + return TRUE; // continue enumeration (otherwise this would be false) +} + +BOOL CShellExt::LoadMenuIcon() +{ + char vimExeFile[BUFSIZE]; + getGvimName(vimExeFile, 1); + if (vimExeFile[0] == '\0') + return FALSE; + HICON hVimIcon; + if (ExtractIconEx(vimExeFile, 0, NULL, &hVimIcon, 1) == 0) + return FALSE; + m_hVimIconBitmap = IconToBitmap(hVimIcon, + GetSysColorBrush(COLOR_MENU), + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON)); + return TRUE; +} + + static char * +searchpath(char *name) +{ + static char widename[2 * BUFSIZE]; + static char location[2 * BUFSIZE + 2]; + + // There appears to be a bug in FindExecutableA() on Windows NT. + // Use FindExecutableW() instead... + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)name, -1, + (LPWSTR)widename, BUFSIZE); + if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"", + (LPWSTR)location) > (HINSTANCE)32) + { + WideCharToMultiByte(CP_ACP, 0, (LPWSTR)location, -1, + (LPSTR)widename, 2 * BUFSIZE, NULL, NULL); + return widename; + } + return (char *)""; +} + + +STDMETHODIMP CShellExt::InvokeSingleGvim(HWND hParent, + LPCWSTR workingDir, + LPCSTR /* pszCmd */, + LPCSTR /* pszParam */, + int /* iShowCmd */, + int gvimExtraOptions) +{ + wchar_t m_szFileUserClickedOn[BUFSIZE]; + wchar_t *cmdStrW; + size_t cmdlen; + size_t len; + UINT i; + + cmdlen = BUFSIZE; + cmdStrW = (wchar_t *) malloc(cmdlen * sizeof(wchar_t)); + if (cmdStrW == NULL) + return E_FAIL; + getGvimInvocationW(cmdStrW); + + if (gvimExtraOptions == EDIT_WITH_VIM_IN_DIFF_MODE) + wcscat(cmdStrW, L" -d"); + else if (gvimExtraOptions == EDIT_WITH_VIM_USE_TABPAGES) + wcscat(cmdStrW, L" -p"); + for (i = 0; i < cbFiles; i++) + { + DragQueryFileW((HDROP)medium.hGlobal, + i, + m_szFileUserClickedOn, + sizeof(m_szFileUserClickedOn)); + + len = wcslen(cmdStrW) + wcslen(m_szFileUserClickedOn) + 4; + if (len > cmdlen) + { + cmdlen = len + BUFSIZE; + wchar_t *cmdStrW_new = (wchar_t *)realloc(cmdStrW, cmdlen * sizeof(wchar_t)); + if (cmdStrW_new == NULL) + { + free(cmdStrW); + return E_FAIL; + } + cmdStrW = cmdStrW_new; + } + wcscat(cmdStrW, L" \""); + wcscat(cmdStrW, m_szFileUserClickedOn); + wcscat(cmdStrW, L"\""); + } + + STARTUPINFOW si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + + // Start the child process. + if (!CreateProcessW(NULL, // No module name (use command line). + cmdStrW, // Command line. + NULL, // Process handle not inheritable. + NULL, // Thread handle not inheritable. + FALSE, // Set handle inheritance to FALSE. + 0, // No creation flags. + NULL, // Use parent's environment block. + workingDir, // Use parent's starting directory. + &si, // Pointer to STARTUPINFO structure. + &pi) // Pointer to PROCESS_INFORMATION structure. + ) + { + MessageBox( + hParent, + _("Error creating process: Check if gvim is in your path!"), + _("gvimext.dll error"), + MB_OK); + } + else + { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + free(cmdStrW); + + return NOERROR; +} diff --git a/src/GvimExt/gvimext.def b/src/GvimExt/gvimext.def new file mode 100644 index 0000000..e6d66f4 --- /dev/null +++ b/src/GvimExt/gvimext.def @@ -0,0 +1,8 @@ +;gvimdef.def : Declares the module parameters for the DLL. + +LIBRARY gvimext +; DESCRIPTION 'Vim Shell Extension' + +EXPORTS + DllCanUnloadNow private + DllGetClassObject private diff --git a/src/GvimExt/gvimext.h b/src/GvimExt/gvimext.h new file mode 100644 index 0000000..b85f32e --- /dev/null +++ b/src/GvimExt/gvimext.h @@ -0,0 +1,168 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved gvimext by Tianmiao Hu + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * If you have any questions or any suggestions concerning gvimext, please + * contact Tianmiao Hu: tianmiao@acm.org. + */ + +#if !defined(AFX_STDAFX_H__3389658B_AD83_11D3_9C1E_0090278BBD99__INCLUDED_) +#define AFX_STDAFX_H__3389658B_AD83_11D3_9C1E_0090278BBD99__INCLUDED_ + +#if defined(_MSC_VER) && _MSC_VER > 1000 +#pragma once +#endif + +// Insert your headers here +// #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +//-------------------------------------------------------------- +// common user interface routines +// +// +//-------------------------------------------------------------- + +#ifndef STRICT +# define STRICT +#endif + +#define INC_OLE2 // MS-Windows, get ole2 from windows.h + +/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# define _CRT_SECURE_NO_DEPRECATE +# define _CRT_NONSTDC_NO_DEPRECATE +#endif + +#include +#include +#include +#include + +#define ResultFromShort(i) ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(i))) + +// Initialize GUIDs (should be done only and at-least once per DLL/EXE) +// +#pragma data_seg(".text") +#define INITGUID +#include + +// +// The class ID of this Shell extension class. +// +// class id: {51EEE242-AD87-11d3-9C1E-0090278BBD99} +// +// +// NOTE!!! If you use this shell extension as a starting point, +// you MUST change the GUID below. Simply run UUIDGEN.EXE +// to generate a new GUID. +// + +// {51EEE242-AD87-11d3-9C1E-0090278BBD99} +// static const GUID <> = +// { 0x51eee242, 0xad87, 0x11d3, { 0x9c, 0x1e, 0x0, 0x90, 0x27, 0x8b, 0xbd, 0x99 } }; +// +// + +// {51EEE242-AD87-11d3-9C1E-0090278BBD99} +// IMPLEMENT_OLECREATE(<>, <>, +// 0x51eee242, 0xad87, 0x11d3, 0x9c, 0x1e, 0x0, 0x90, 0x27, 0x8b, 0xbd, 0x99); +// + +// {51EEE242-AD87-11d3-9C1E-0090278BBD99} -- this is the registry format +DEFINE_GUID(CLSID_ShellExtension, 0x51eee242, 0xad87, 0x11d3, 0x9c, 0x1e, 0x0, 0x90, 0x27, 0x8b, 0xbd, 0x99); + +// this class factory object creates context menu handlers for windows 32 shell +class CShellExtClassFactory : public IClassFactory +{ +protected: + ULONG m_cRef; + +public: + CShellExtClassFactory(); + ~CShellExtClassFactory(); + + //IUnknown members + STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + //IClassFactory members + STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *); + STDMETHODIMP LockServer(BOOL); + +}; +typedef CShellExtClassFactory *LPCSHELLEXTCLASSFACTORY; +#define MAX_HWND 100 + +// this is the actual OLE Shell context menu handler +class CShellExt : public IContextMenu, + IShellExtInit +{ +private: + BOOL LoadMenuIcon(); + +protected: + ULONG m_cRef; + LPDATAOBJECT m_pDataObj; + UINT m_edit_existing_off; + HBITMAP m_hVimIconBitmap; + + // For some reason, this callback must be static + static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam); + + STDMETHODIMP PushToWindow(HWND hParent, + LPCSTR pszWorkingDir, + LPCSTR pszCmd, + LPCSTR pszParam, + int iShowCmd, + int idHWnd); + + STDMETHODIMP InvokeSingleGvim(HWND hParent, + LPCWSTR workingDir, + LPCSTR pszCmd, + LPCSTR pszParam, + int iShowCmd, + int gvimExtraOptions); + +public: + int m_cntOfHWnd; + HWND m_hWnd[MAX_HWND]; + CShellExt(); + ~CShellExt(); + + //IUnknown members + STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + //IShell members + STDMETHODIMP QueryContextMenu(HMENU hMenu, + UINT indexMenu, + UINT idCmdFirst, + UINT idCmdLast, + UINT uFlags); + + STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi); + + STDMETHODIMP GetCommandString(UINT_PTR idCmd, + UINT uFlags, + UINT FAR *reserved, + LPSTR pszName, + UINT cchMax); + + //IShellExtInit methods + STDMETHODIMP Initialize(LPCITEMIDLIST pIDFolder, + LPDATAOBJECT pDataObj, + HKEY hKeyID); +}; + +typedef CShellExt *LPCSHELLEXT; +#pragma data_seg() + +#endif diff --git a/src/GvimExt/gvimext.inf b/src/GvimExt/gvimext.inf new file mode 100644 index 0000000..8b45bb1 --- /dev/null +++ b/src/GvimExt/gvimext.inf @@ -0,0 +1,22 @@ +[Version] +Signature="$Windows NT$"" +Provider="Tianmiao" + +[Manufacture] + +[DefaultInstall] +AddReg=ThisDll.Add.Reg + +[DefaultUninstall] +DelReg=ThisDLL.Add.Reg + +[ThisDll.Add.Reg] +HKCR,CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99} +HKCR,CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\InProcServer32 +HKCR,*\shellex\ContextMenuHandlers\gvim +HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved",{51EEE242-AD87-11d3-9C1E-0090278BBD99} +HKLM,Software\Vim\Gvim +HKLM,"Software\Microsoft\Windows\CurrentVersion\Uninstall\Vim 6.0" + +[Strings] +ThisDll="gvimext.dll" diff --git a/src/GvimExt/gvimext.rc b/src/GvimExt/gvimext.rc new file mode 100644 index 0000000..10476da --- /dev/null +++ b/src/GvimExt/gvimext.rc @@ -0,0 +1,109 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winresrc.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x3L +#else + FILEFLAGS 0x2L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Developed using COM architecture!\0" + VALUE "CompanyName", "Tianmiao Hu's Developer Studio\0" + VALUE "FileDescription", "A small project for the context menu of gvim!\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "gvim right-click menu extension\0" + VALUE "LegalCopyright", "Copyright © 1999 Tianmiao Hu\0" + VALUE "LegalTrademarks", "Tianmiao Hu's Gvim Context Menu Extension\0" + VALUE "OriginalFilename", "gvimext.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Tianmiao Hu's gvimext context menu extension\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/GvimExt/gvimext_ming.def b/src/GvimExt/gvimext_ming.def new file mode 100644 index 0000000..b96e1d3 --- /dev/null +++ b/src/GvimExt/gvimext_ming.def @@ -0,0 +1,10 @@ +;gvimdef_ming.def : Declares the module parameters for the DLL. +;The mingw environment doesn't know anything about private declarations +;Hence this is the same file as gvimext.def with private removed + +LIBRARY gvimext +; DESCRIPTION 'Vim Shell Extension build with MinGW' + +EXPORTS + DllCanUnloadNow = DllCanUnloadNow@0 + DllGetClassObject = DllGetClassObject@12 diff --git a/src/GvimExt/gvimext_ming.rc b/src/GvimExt/gvimext_ming.rc new file mode 100644 index 0000000..6c69854 --- /dev/null +++ b/src/GvimExt/gvimext_ming.rc @@ -0,0 +1,45 @@ +#include +#define xstr(x) str(x) +#define str(x) #x +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x3L +#else + FILEFLAGS 0x2L +#endif + FILEOS 0x4L + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +{ + BLOCK "StringFileInfo" + { + BLOCK "040904b0" + { + VALUE "Comments", "Developed using COM architecture!\0" + VALUE "CompanyName", "Tianmiao Hu's Developer Studio\0" + VALUE "FileDescription", "A small project for the context menu of gvim!\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "gvim right-click menu extension\0" + VALUE "LegalCopyright", "Copyright © 1999 Tianmiao Hu\0" + VALUE "LegalTrademarks", "Tianmiao Hu's Gvim Context Menu Extension\0" + VALUE "OriginalFilename", "gvimext.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Tianmiao Hu's gvimext context menu extension\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + +#if defined(__GNUC__) + VALUE "SpecialBuild", "Build With " "MingW " xstr(__GNUC__) "." xstr(__GNUC_MINOR__) "." xstr(__GNUC_PATCHLEVEL__) " on " __DATE__ " " __TIME__ "\0" +#else + VALUE "SpecialBuild", "Unknown compiler\0" + +#endif + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x409, 1200 + } +} diff --git a/src/GvimExt/resource.h b/src/GvimExt/resource.h new file mode 100644 index 0000000..8ddc823 --- /dev/null +++ b/src/GvimExt/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by gvimext.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/GvimExt/uninst.bat b/src/GvimExt/uninst.bat new file mode 100644 index 0000000..71d14f6 --- /dev/null +++ b/src/GvimExt/uninst.bat @@ -0,0 +1 @@ +rundll32.exe setupapi,InstallHinfSection DefaultUninstall 128 %1 diff --git a/src/INSTALL b/src/INSTALL new file mode 100644 index 0000000..efa03da --- /dev/null +++ b/src/INSTALL @@ -0,0 +1,221 @@ +INSTALL - Installation of Vim on different machines. + +This file contains instructions for compiling Vim. If you already have an +executable version of Vim, you don't need this. + +Contents: +1. Generic +2. Unix +3. OS/2 (with EMX 0.9b) +4. Atari MiNT + +See INSTALLami.txt for Amiga +See INSTALLmac.txt for Macintosh +See INSTALLpc.txt for PC (Windows XP/Vista/7/8/10) +See INSTALLvms.txt for VMS +See INSTALLx.txt for cross-compiling on Unix +See ../READMEdir/README_390.txt for z/OS and OS/390 Unix +See ../runtime/doc/os_haiku.txt for Haiku + +1. Generic +========== + +If you compile Vim without specifying anything, you will get the default +behaviour as is documented, which should be fine for most people. + +For features that you can't enable/disable in another way, you can edit the +file "feature.h" to match your preferences. + + +2. Unix +======= + +Summary: +1. make run configure, compile and link +2. make install installation in /usr/local + +This will include the GUI and X11 libraries, if you have them. If you want a +version of Vim that is small and starts up quickly, see the Makefile for how +to disable the GUI and X11. If you don't have GUI libraries and/or X11, these +features will be disabled automatically. + +To build Vim on Ubuntu from scratch on a clean system using git: + Install tools required to be able to get and build Vim: + % sudo apt install git + % sudo apt install make + % sudo apt install clang + % sudo apt install libtool-bin + + Build Vim with default features: + % git clone https://github.com/vim/vim.git + % cd vim/src + % make + + Run tests to check there are no problems: + % make test + + Install Vim in /usr/local: + % sudo make install + + Add X windows clipboard support (also needed for GUI): + % sudo apt install libxt-dev + % make reconfig + + Add GUI support: + % sudo apt install libgtk-3-dev + % make reconfig + + Add Python 3 support: + % sudo apt install libpython3-dev + Uncomment this line in Makefile: + "CONF_OPT_PYTHON3 = --enable-python3interp" + % make reconfig + + Debugging: + % sudo apt install valgrind + Uncomment this line in Makefile: + CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 + % make reconfig + % make test_{test-name} + See output in testdir/valgrind.test_{test-name} + + +See the start of Makefile for more detailed instructions about how to compile +Vim. + +If you need extra compiler and/or linker arguments, set $CFLAGS and/or $LIBS +before starting configure. Example: + + env CFLAGS=-I/usr/local/include LIBS=-lm make + +This is only needed for things that configure doesn't offer a specific argument +for or figures out by itself. First try running configure without extra +arguments. + +GNU Autoconf and a few other tools have been used to make Vim work on many +different Unix systems. The advantage of this is that Vim should compile +on most systems without any adjustments. The disadvantage is that when +adjustments are required, it takes some time to understand what is happening. + +If configure finds all library files and then complains when linking that some +of them can't be found, your linker doesn't return an error code for missing +libraries. Vim should be linked fine anyway, mostly you can just ignore these +errors. + +If you run configure by hand (not using the Makefile), remember that any +changes in the Makefile have no influence on configure. This may be what you +want, but maybe not! + +The advantage of running configure separately, is that you can write a script +to build Vim, without changing the Makefile or feature.h. Example (using sh): + + CFLAGS=-DCOMPILER_FLAG ./configure --enable-gui=motif + +One thing to watch out for: If the configure script itself changes, running +"make" will execute it again, but without your arguments. Do "make clean" and +run configure again. + +If you are compiling Vim for several machines, for each machine: + a. make shadow + b. mv shadow machine_name + c. cd machine_name + d. make; make install + +[Don't use a path for machine_name, just a directory name, otherwise the links +that "make shadow" creates won't work.] + + +Unix: COMPILING WITH/WITHOUT GUI + +NOTE: This is incomplete, look in Makefile for more info. + +These configure arguments can be used to select which GUI to use: +--enable-gui=gtk or: gtk2, motif, athena or auto +--disable-gtk-check +--disable-motif-check +--disable-athena-check + +This configure argument can be used to disable the GUI, even when the necessary +files are found: +--disable-gui + +--enable-gui defaults to "auto", so it will automatically look for a GUI (in +the order of GTK, Motif, then Athena). If one is found, then it is used and +does not proceed to check any of the remaining ones. Otherwise, it moves on +to the next one. + +--enable-{gtk,gtk2,kde,motif,athena}-check all default to "yes", such that if +--enable-gui is "auto" (which it is by default), GTK, Motif, and Athena will +be checked for. If you want to *exclude* a certain check, then you use +--disable-{gtk,gtk2,kde,motif,athena}-check. + +For example, if --enable-gui is set to "auto", but you don't want it look for +Motif, you then also specify --disable-motif-check. This results in only +checking for GTK and Athena. + +Lastly, if you know which one you want to use, then you can just do +--enable-gui={gtk,gtk2,kde,motif,athena}. So if you wanted to only use Motif, +then you'd specify --enable-gui=motif. Once you specify what you want, the +--enable-{gtk,gtk2,kde,motif,athena}-check options are ignored. + +On Linux you usually need GUI "-devel" packages. You may already have GTK +libraries installed, but that doesn't mean you can compile Vim with GTK, you +also need the header files. + +For compiling with the GTK+ GUI, you need a recent version of glib and gtk+. +Configure checks for at least version 1.1.16. An older version is not selected +automatically. If you want to use it anyway, run configure with +"--disable-gtktest". +GTK requires an ANSI C compiler. If you fail to compile Vim with GTK+ (it +is the preferred choice), try selecting another one in the Makefile. +If you are sure you have GTK installed, but for some reason configure says you +do not, you may have left-over header files and/or library files from an older +(and incompatible) version of GTK. if this is the case, please check +auto/config.log for any error messages that may give you a hint as to what's +happening. + +There used to be a KDE version of Vim, using Qt libraries, but since it didn't +work very well and there was no maintainer it was dropped. + + +Unix: COMPILING ON LINUX + +On Linux, when using -g to compile (which is default for gcc), the executable +will probably be statically linked. If you don't want this, remove the -g +option from CFLAGS. + +Unix: PUTTING vimrc IN /etc + +Some Linux distributions prefer to put the global vimrc file in /etc, and the +Vim runtime files in /usr. This can be done with: + ./configure --prefix=/usr + make VIMRCLOC=/etc VIMRUNTIMEDIR=/usr/share/vim MAKE="make -e" + +Unix: COMPILING ON NeXT + +Add the "-posix" argument to the compiler by using one of these commands: + setenv CC 'cc -posix' (csh) + export CC='cc -posix' (sh) +And run configure with "--disable-motif-check". + +Unix: LOCAL HEADERS AND LIBRARIES NOT IN /usr/local + +Sometimes it is necessary to search different path than /usr/local for locally +installed headers (/usr/local/include) and libraries (/usr/local/lib). +To search /stranger/include and /stranger/lib for locally installed +headers and libraries, use: + ./configure --with-local-dir=/stranger +And to not search for locally installed headers and libraries at all, use: + ./configure --without-local-dir + + +3. OS/2 +======= + +OS/2 support was removed in patch 7.4.1008 + + +4. Atari MiNT +============= + +Atari MiNT support was removed in patch 8.2.1215. diff --git a/src/INSTALLami.txt b/src/INSTALLami.txt new file mode 100644 index 0000000..a2c9faf --- /dev/null +++ b/src/INSTALLami.txt @@ -0,0 +1,19 @@ +INSTALLami.txt - Installation of Vim from source on Amiga and MorphOS + +This file contains instructions for compiling Vim. If you already have an +executable version of Vim, you don't need this. + +The file "feature.h" can be edited to match your preferences. You can skip +this, then you will get the default behavior as is documented, which should +be fine for most people. + +Summary: +make -f Make_ami.mak gcc +make -f Make_ami.mak CC=vc vbcc + +Please note that currently only gcc has been tested. VBCC would need its own +CFLAGS, but should otherwise work out of the box. For cross-compiling, UNM +can be used to override uname and thereby set the target. An example is shown +below: + +make -f Make_ami.mak CC=ppc-morphos-gcc UNM=MorphOS diff --git a/src/INSTALLmac.txt b/src/INSTALLmac.txt new file mode 100644 index 0000000..9980d25 --- /dev/null +++ b/src/INSTALLmac.txt @@ -0,0 +1,83 @@ +INSTALLmac.txt - Installation of Vim on Apple MacOS + +This file contains instructions for compiling Vim. If you already have an +executable version of Vim, you don't need this. + +MacOS Classic is no longer supported. If you really want it use Vim 6.4. +Only '/' is supported as path separator. + + +---------------------------------------------------------------------------- +Prerequisites +---------------------------------------------------------------------------- + +Make sure you've installed Xcode and CommandLineTools. You can download Xcode +from the Mac App Store, for free. + +To check for CommandLineTools open a terminal and do: + + $ make --version + +If not installed yet a window pops up instructing you to install the developer +tools. + +If you don't have the source yet, best is to use git (which you need to +install first), see http://www.vim.org/git.php +Or you can download and unpack the Unix tar archive, see + http://www.vim.org/download.php + + +---------------------------------------------------------------------------- +Build and install the terminal version. +---------------------------------------------------------------------------- + +You can compile vim with the standard Unix routine: + cd vim/src + make + make test + sudo make install + +If you get an error "glibtool: command not found" search on stackoverflow for +mac-osx-where-can-i-download-glibtool. + +With Homebrew, run: + + brew install libtool + +To build libtool from source: + + 1. Download the source code from https://www.gnu.org/software/libtool/. + + 2. Run these commands from the root of the source code directory: + + ./configure --program-prefix=g + make + sudo make install + + +---------------------------------------------------------------------------- +Build and install the GUI version with X-Windows +---------------------------------------------------------------------------- + +First, install XQuartz, which you can download from https://www.xquartz.org. + +To tell configure to use a GUI you can edit the Makefile and uncomment these +two lines (remove the # at the start of the line): + + CONF_OPT_GUI = --enable-gui=athena + CONF_OPT_DARWIN = --disable-darwin + +Do "make distclean" to start with a clean slate. +Then build as with the terminal version above. +Instead of "athena" you can try "gtk2" but you probably need to install GTK +first. + + +---------------------------------------------------------------------------- +Notes +---------------------------------------------------------------------------- + +Mac-specific configure options are explained in the Makefile: + --disable-darwin + --with-mac-arch + diff --git a/src/INSTALLpc.txt b/src/INSTALLpc.txt new file mode 100644 index 0000000..104a3a9 --- /dev/null +++ b/src/INSTALLpc.txt @@ -0,0 +1,998 @@ +INSTALLpc.txt - Installation of Vim on PC + +This file contains instructions for compiling Vim. If you already have an +executable version of Vim, you don't need this. + +You can find the latest here: https://github.com/vim/vim-win32-installer +This page also has links to install support for interfaces such as Perl, +Python, Lua, etc. + +The file "feature.h" can be edited to match your preferences. You can skip +this, then you will get the default behavior as is documented, which should +be fine for most people. + +This document assumes that you are building Vim for Win32 or later (Windows +7/8/10/11). There are also instructions for pre-Vista and pre-XP systems, but +they might no longer work. + +The recommended way is to build a 32 bit Vim, also on 64 bit systems. You can +build a 64 bit Vim if you like, the executable will be bigger and Vim won't be +any faster, but you can edit files larger than 2 Gbyte. + + +Contents: +1. Microsoft Visual C++ +2. Using MSYS2 with MinGW +3. Using MinGW +4. Cygwin +5. Cross compiling for Win32 from a Linux machine +6. Building with Python support +7. Building with Python3 support +8. Building with Racket or MzScheme support +9. Building with Lua support +10. Building with Perl support +11. Building with Ruby support +12. Building with Tcl support +13. Building with DirectX (DirectWrite) support +14. Building with libsodium support +15. Windows 3.1 +16. MS-DOS + +17. Installing after building from sources + + +The currently recommended way (that means it has been verified to work) is +using the "Visual Studio 2022 Community Edition" installation. This doesn't +include the SDK for older Windows versions (95 - XP), see "OLDER VERSIONS" +below for that. + + +1. Microsoft Visual C++ +======================= + +We do not provide download links, since Microsoft keeps changing them. You +can search for "Visual Studio 2022 Community Edition", for example. You will +need to create a Microsoft account (it's free). You need to download the +"DVD", and execute the installer from it. + +When installing "Visual Studio 2022 Community Edition" or "Build Tools for +Visual Studio 2022" make sure to select "custom" and check all checkboxes +under "Universal Windows App Development Tools". Or whatever they are called +now. + +Note: Vim source code no longer supports Windows XP since Patch 9.0.0496. +Also, Visual Studio 2017 was the last version to support a Windows XP target. +If you still want to target Windows XP, you can check out an older version of +vim source code and install Visual Studio 2017 or 2015 - making sure to check +the checkbox for "Windows XP Support for C++". Additional build instructions +for Windows XP are provided below. |new-msvc-windows-xp| + + +Visual Studio +------------- + +Building with Visual Studio (VS2015, VS2017, VS2019 and VS2022) is +straightforward. Older versions probably don't work. + +Vim versions built with VS2015 and VS2017 are systematically tested and known +to work well on Windows versions 7, 8 and 8.1. + +Vim versions built with VS2015 and VS2017 are also known to work well on all +early versions of Windows 10. However, Vim versions built with VS2015 and +VS2017 may run into a known issue on the latest versions of Windows 10 and 11. +Building Vim with VS2019 or VS2022 resolves the issue. + +Vim versions built with VS2019 and VS2022 are systematically tested and +known to work on Windows versions 7, 8, 8.1, 10, 11 and all respective server +variants. + +Visual Studio installed a batch file called vcvarsall.bat, which you must +run to set up paths for nmake and MSVC. We provide a batch file +"msvc2015.bat" for this. You may need to edit it if you didn't install Visual +Studio in the standard location. +If you use VS2017 or later, you can use "msvc-latest.bat" (or "msvc2017.bat" +and so on for the specific version). You must specify the architecture (e.g. +"x86", "x64", etc.) as the first argument when you use this. If you use VS2017 +Express, you must use "x86_amd64" instead of "x64" for targeting the x64 +platform. + +To build Vim from the command line with MSVC, use Make_mvc.mak. + +nmake -f Make_mvc.mak console Win32 SDK or Microsoft Visual C++ +nmake -f Make_mvc.mak GUI=yes GUI Microsoft Visual C++ +nmake -f Make_mvc.mak OLE=yes OLE Microsoft Visual C++ +nmake -f Make_mvc.mak PERL=C:\Perl PYTHON=C:\Python etc. + Perl, Python, etc. + +Make_mvc.mak allows a Vim to be built with various different features and +debug support. + +For compiling gVim with IME support on far-east Windows, add IME=yes +to the parameters you pass to Make_mvc.mak. + +See the specific files for comments and options. + +These files have been supplied by George V. Reilly, Ben Singer, Ken Scott and +Ron Aaron; they have been tested. But several things changed after that... + + +Targeting Windows XP with MSVC 2015 or 2017 *new-msvc-windows-xp* +------------------------------------------- + +(The support for pre-Vista was removed in patch 9.0.0496. If you want to +target Windows XP, use the source code before that.) + +Beginning with Visual C++ 2012, Microsoft changed the behavior of LINK.EXE +so that it targets Windows 6.0 (Vista) by default. In order to override +this, the target Windows version number needs to be passed to LINK like +follows: + LINK ... /subsystem:console,5.01 + +Make_mvc.mak now supports a macro SUBSYSTEM_VER to pass the Windows version. +Use lines like follows to target Windows XP x86 (assuming using Visual C++ +2012 under 64-bit Windows): + set WinSdk71=%ProgramFiles(x86)%\Microsoft SDKs\Windows\v7.1A + set INCLUDE=%WinSdk71%\Include;%INCLUDE% + set LIB=%WinSdk71%\Lib;%LIB% + set CL=/D_USING_V110_SDK71_ + nmake -f Make_mvc.mak ... WINVER=0x0501 SUBSYSTEM_VER=5.01 + +To target Windows XP x64 instead of x86, you need to change the settings of +LIB and SUBSYSTEM_VER: + ... + set LIB=%WinSdk71%\Lib\x64;%LIB% + ... + nmake -f Make_mvc.mak ... WINVER=0x0501 SUBSYSTEM_VER=5.02 + +If you use Visual C++ 2015 (either Express or Community Edition), executing +msvc2015.bat will set them automatically. For x86 builds run this without +options: + msvc2015 +For x64 builds run this with the "x86_amd64" option: + msvc2015 x86_amd64 +This enables x86_x64 cross compiler. This works on any editions including +Express edition. +If you use Community (or Professional) edition, you can enable the x64 native +compiler by using the "x64" option: + msvc2015 x64 + +The following Visual C++ team blog can serve as a reference page: + http://blogs.msdn.com/b/vcblog/archive/2012/10/08/windows-xp-targeting-with-c-in-visual-studio-2012.aspx + + +Cross compile support for Windows on ARM64 +------------------------------------------ + +This depends on VS2017 with the optional ARM64 compiler and SDK +installed. Use "vcvarsall.bat x64_arm64" as the build environment. + +The ARM64 support was provided by Leendert van Doorn. + + +OLDER VERSIONS + +The minimal supported version is Windows 7. Building with compilers older than +2015 most likely doesn't work. Since MSVC 2022 can be obtained for free there +is no point in supporting older versions. + +If you need the executable to run on Windows 98 or ME, use the 2005 one +|msvc-2005-express|, and use the source code before 8.0.0029. See the +src/INSTALLpc.txt file for instructions. + + +2. MSYS2 with MinGW +=================== + +2.1. Setup the basic msys2 environment + +Go to the official page of MSYS2: https://www.msys2.org +Download an installer: + +* msys2-x86_64-YYYYMMDD.exe for 64-bit Windows + (Even if you want to build 32-bit Vim) +* msys2-i686-YYYYMMDD.exe for 32-bit Windows + +Execute the installer and follow the instructions to update basic packages. +At the end keep the checkbox checked to run msys2 now. If needed, you can +open the window from the start menu, MSYS2 64 bit / MSYS2 MSYS. + +Execute: + $ pacman -Syu + +And restart MSYS2 console (select "MSYS2 MSYS 32-Bit" icon from the Start +Menu for building 32 bit Vim, otherwise select "MSYS2 MinGW 64-Bit"). +Then execute: + $ pacman -Su + +If pacman complains that `catgets` and `libcatgets` conflict with another +package, select `y` to remove them. + + +2.2. Install additional packages for building Vim + +The following package groups are required for building Vim: + +* base-devel +* mingw-w64-i686-toolchain (for building 32-bit Vim) +* mingw-w64-x86_64-toolchain (for building 64-bit Vim) + +(These groups also include some useful packages which are not used by Vim.) +Use the following command to install them: + + $ pacman -S base-devel mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain + +Or you can use the `pacboy` command to avoid long package names: + + $ pacboy -S base-devel: toolchain:m + +The suffix ":" means that it disables the package name translation. +The suffix ":m" means both i686 and x86_64. You can also use the ":i" suffix +to install only i686, and the ":x" suffix to install only x86_64. +(See `pacboy help` for the help.) + +See also the pacman page in ArchWiki for the general usage of pacman: + https://wiki.archlinux.org/index.php/pacman + +MSYS2 has its own git package, and you can also install it via pacman: + + $ pacman -S git + + +2.3. Keep the build environment up-to-date + +After you have installed the build environment, you may want to keep it +up-to-date (E.g. always use the latest GCC). +In that case, you just need to execute the command: + $ pacman -Syu + + +2.4. Build Vim + +Select one of the following icon from the Start Menu: + +* MSYS2 MinGW 32-bit (To build 32-bit versions of Vim) +* MSYS2 MinGW 64-bit (To build 64-bit versions of Vim) + +Go to the source directory of Vim, then execute the make command. E.g.: + + make -f Make_ming.mak + make -f Make_ming.mak GUI=no + make -f Make_ming.mak GUI=no DEBUG=yes + +NOTE: you can't execute vim.exe in the MSYS2 console, open a normal Windows +console for that. You need to set $PATH to be able to build there, e.g.: + + set PATH=c:\msys64\mingw32\bin;c:\msys64\usr\bin;%PATH% + +This command is in msys32.bat. Or for the 64 bit compiler use msys64.bat: + + set PATH=c:\msys64\mingw64\bin;c:\msys64\usr\bin;%PATH% + +If you have msys64 in another location you will need to adjust the paths for +that. + +2.5. Build Vim with Clang + +The following package group is required for building Vim with Clang: + +* mingw-w64-clang-x86_64-clang + +Use the following command to install it: + + $ pacman -S mingw-w64-clang-x86_64-clang + +Go to the source directory of Vim, then execute the make command. E.g.: + + CC=clang + CXX=clang++ + # To build Vim without the GUI support + make -f Make_ming.mak GUI=no + # To build Vim with the GUI support + make -f Make_ming.mak GUI=yes XPM=no + +To build Vim with the address sanitizer (ASAN), execute the following command: + + CC=clang + CXX=clang++ + make -f Make_ming.mak DEBUG=yes ASAN=yes + +3. MinGW +======== + +(written by Ron Aaron: , updated by Ken Takata, et al.) + +This is about how to produce a Win32 binary of gvim with MinGW from the normal +Command Prompt window. (To use MSYS2 console, see above.) + +First, you need to get the 'MinGW-w64' compiler, which is free for the +download at: + + http://mingw-w64.sourceforge.net/ + +Or a compiler provided on msys2: + + https://www.msys2.org/ + +The original 'mingw32' compiler is outdated, and may no longer work: + + http://www.mingw.org/ + +Once you have downloaded the compiler binaries, unpack them on your hard disk +somewhere, and put them on your PATH. Go to the Control Panel, (Performance +and Maintenance), System, Advanced, and edit the environment from there. If +you use the standalone MinGW-w64 compiler, the path may depend on your +installation. If you use msys2 compilers, set your installed paths (normally +one of the following): + + C:\msys32\mingw32\bin (32-bit msys2, targeting 32-bit builds) + C:\msys64\mingw32\bin (64-bit msys2, targeting 32-bit builds) + C:\msys64\mingw64\bin (64-bit msys2, targeting 64-bit builds) + +Test if gcc is on your path. From a Command Prompt window: + + C:\> gcc --version + gcc (GCC) 4.8.1 + + C:\> mingw32-make --version + GNU Make 3.82.90 (...etc...) + +Now you are ready to rock 'n' roll. Unpack the vim sources (look on +www.vim.org for exactly which version of the vim files you need). + +Change directory to 'vim\src': + + C:\> cd vim\src + C:\VIM\SRC> + +and you type: + + mingw32-make -f Make_ming.mak gvim.exe + +After churning for a while, you will end up with 'gvim.exe' in the 'vim\src' +directory. + +You should not need to do *any* editing of any files to get vim compiled this +way. If, for some reason, you want the console-mode-only version of vim (this +is NOT recommended on Win32, especially on '95/'98!!!), you can use: + + mingw32-make -f Make_ming.mak GUI=no vim.exe + +If you are dismayed by how big the EXE is, I strongly recommend you get 'UPX' +(also free!) and compress the file (typical compression is 50%). UPX can be +found at + http://www.upx.org/ + +As of 2011, UPX still does not support compressing 64-bit EXE's; if you have +built a 64-bit vim then an alternative to UPX is 'MPRESS'. MPRESS can be found +at: + http://www.matcode.com/mpress.htm + + +ADDITION: NLS support with MinGW + +(by Eduardo F. Amatria ) + +If you want National Language Support, read the file src/po/README_mingw.txt. +You need to uncomment lines in Make_ming.mak to have NLS defined. + + +4. Cygwin +========= + +Use Make_cyg.mak with Cygwin's GCC. See + http://users.skynet.be/antoine.mechelynck/vim/compile.htm + +With Cygnus gcc you should use the Unix Makefile instead (you need to get the +Unix archive then). Then you get a Cygwin application (feels like Vim is +running on Unix), while with Make_cyg.mak you get a Windows application (like +with the other makefiles). + + +5. Cross compiling for Win32 from a Linux machine +================================================= + +[Update of 1) needs to be verified] + +If you like, you can compile the 'mingw' Win32 version from the comfort of +your Linux (or other unix) box. To do this, you need to follow a few steps: + 1) Install the mingw32 cross-compiler. See + http://www.mingw.org/wiki/LinuxCrossMinGW + http://www.libsdl.org/extras/win32/cross/README.txt + 2) Get and unpack both the Unix sources and the extra archive + 3) in 'Make_cyg_ming.mak', set 'CROSS' to 'yes' instead of 'no'. + Make further changes to 'Make_cyg_ming.mak' and 'Make_ming.mak' as you + wish. If your cross-compiler prefix differs from the predefined value, + set 'CROSS_COMPILE' corresponding. + 4) make -f Make_ming.mak gvim.exe + +Now you have created the Windows binary from your Linux box! Have fun... + + +6. Building with Python support +=============================== + +For building with MSVC the "Windows Installer" from www.python.org works fine. + +When building, you need to set the following variables at least: + + PYTHON: Where Python is installed. E.g. C:\Python27 + DYNAMIC_PYTHON: Whether dynamic linking is used. Usually, set to yes. + PYTHON_VER: Python version. E.g. 27 for Python 2.7.X. + +E.g. When using MSVC (as one line): + + nmake -f Make_mvc.mak + PYTHON=C:\Python27 DYNAMIC_PYTHON=yes PYTHON_VER=27 + +When using MinGW and link with the official Python (as one line): + + mingw32-make -f Make_ming.mak + PYTHON=C:/Python27 DYNAMIC_PYTHON=yes PYTHON_VER=27 + +When using msys2 and link with Python2 bundled with msys2 (as one line): + + mingw32-make -f Make_ming.mak PYTHON=c:/msys64/mingw64 + PYTHON_HOME=c:/msys64/mingw64 + PYTHONINC=-Ic:/msys64/mingw64/include/python2.7 + DYNAMIC_PYTHON=yes + PYTHON_VER=27 + DYNAMIC_PYTHON_DLL=libpython2.7.dll + STATIC_STDCPLUS=yes + +(This is for 64-bit builds. For 32-bit builds, replace mingw64 with mingw32.) +(STATIC_STDCPLUS is optional. Set to yes if you don't want to require +libstdc++-6.dll.) + + +(rest written by Ron Aaron: ) + +Building with the mingw32 compiler, and the ActiveState ActivePython: + http://www.ActiveState.com/Products/ActivePython/ + +After installing the ActivePython, you will have to create a 'mingw32' +'libpython20.a' to link with: + cd $PYTHON/libs + pexports python20.dll > python20.def + dlltool -d python20.def -l libpython20.a + +Once that is done, edit the 'Make_ming.mak' so the PYTHON variable points to +the root of the Python installation (C:\Python20, for example). If you are +cross-compiling on Linux with the mingw32 setup, you need to also convert all +the 'Include' files to *unix* line-endings. This bash command will do it +easily: + for fil in *.h ; do vim -e -c 'set ff=unix|w|q' $fil + +Now just do: + make -f Make_ming.mak gvim.exe + +You will end up with a Python-enabled, Win32 version. Enjoy! + + +7. Building with Python3 support +================================ + +For building with MSVC the "Windows Installer" from www.python.org works fine. +Python 3.6 is recommended. + +When building, you need to set the following variables at least: + + PYTHON3: Where Python3 is installed. E.g. C:\Python36 + DYNAMIC_PYTHON3: Whether dynamic linking is used. Usually, set to yes. + PYTHON3_VER: Python3 version. E.g. 36 for Python 3.6.X. + +E.g. When using MSVC (as one line): + + nmake -f Make_mvc.mak + PYTHON3=C:\Python36 DYNAMIC_PYTHON3=yes PYTHON3_VER=36 + +When using MinGW and link with the official Python3 (as one line): + + mingw32-make -f Make_ming.mak + PYTHON3=C:/Python36 DYNAMIC_PYTHON3=yes PYTHON3_VER=36 + +When using msys2 and link with Python3 bundled with msys2 (as one line): + + mingw32-make -f Make_ming.mak PYTHON3=c:/msys64/mingw64 + PYTHON3_HOME=c:/msys64/mingw64 + PYTHON3INC=-Ic:/msys64/mingw64/include/python3.6m + DYNAMIC_PYTHON3=yes + PYTHON3_VER=36 + DYNAMIC_PYTHON3_DLL=libpython3.6m.dll + STATIC_STDCPLUS=yes + +(This is for 64-bit builds. For 32-bit builds, replace mingw64 with mingw32.) +(STATIC_STDCPLUS is optional. Set to yes if you don't want to require +libstdc++-6.dll.) + + +8. Building with Racket or MzScheme support +=========================================== + +1) Building with Racket support (newest) + +MzScheme and PLT Scheme names have been rebranded as Racket. Vim with Racket +support can be built with either MSVC or MinGW (or Cygwin). +Get it from https://download.racket-lang.org/ + +Copy lib/libracket{version}.dll to your Windows system directory. The system +directory depends on your Windows bitness and Vim bitness: + 32-bit Vim on 32-bit Windows: C:\Windows\System32 + 32-bit Vim on 64-bit Windows: C:\Windows\SysWOW64 + 64-bit Vim on 64-bit Windows: C:\Windows\System32 + +For building you need to set the following variables: + + MZSCHEME: Where Racket is installed. + E.g. C:\Program Files (x86)\Racket + DYNAMIC_MZSCHEME: Whether dynamic linking is used. Usually, set to yes. + MZSCHEME_VER: Racket DLL version which is used for the file name. + See below for a list of MZSCHEME_VER. + The DLL can be found under the lib directory. E.g. + C:\Program Files (x86)\Racket\lib\libracket3m_XXXXXX.dll + MZSCHEME_COLLECTS: (Optional) Path of the collects directory used at + runtime. Default: $(MZSCHEME)\collects + User can override this with the PLTCOLLECTS environment + variable. + +List of MZSCHEME_VER (incomplete): + + Racket ver. | MZSCHEME_VER + ========================== + 6.3 | 3m_9z0ds0 + 6.6 | 3m_a0solc + 6.8 | 3m_a1zjsw + 6.10 | 3m_a36fs8 + + +E.g. When using MSVC (as one line): + + nmake -f Make_mvc.mak + MZSCHEME="C:\Program Files (x86)\Racket" DYNAMIC_MZSCHEME=yes + MZSCHEME_VER=3m_9z0ds0 + +Or when using MinGW (as one line): + + mingw32-make -f Make_ming.mak + MZSCHEME='C:/Program\ Files\ (x86)/Racket' DYNAMIC_MZSCHEME=yes + MZSCHEME_VER=3m_9z0ds0 + + Spaces should be escaped with '\'. + + +2) Building with MzScheme support (older) + +(written by Sergey Khorev ) + +Vim with MzScheme (http://www.plt-scheme.org/software/mzscheme) support can +be built with either MSVC, or MinGW, or Cygwin. Supported versions are 205 and +above (including 299 and 30x series). + +The MSVC build is quite straightforward. Simply invoke (in one line) +nmake -fMake_mvc.mak MZSCHEME= + [MZSCHEME_VER=] [DYNAMIC_MZSCHEME=] +where is the last seven characters from MzScheme dll name +(libmzschXXXXXXX.dll). +If DYNAMIC_MZSCHEME=yes, resulting executable will not depend on MzScheme +DLL's, but will load them in runtime on demand. + +Building dynamic MzScheme support on MinGW and Cygwin is similar. Take into +account that should contain slashes rather than backslashes +(e.g. d:/Develop/MzScheme) + +"Static" MzScheme support (Vim executable will depend on MzScheme DLLs +explicitly) on MinGW and Cygwin requires additional step. + +libmzschXXXXXXX.dll and libmzgcXXXXXXX.dll should be copied from +%WINDOWS%\System32 to other location (either build directory, some temporary +dir or even MzScheme home). + +Pass that path as MZSCHEME_DLLS parameter for Make. E.g., +make -f Make_cyg.mak MZSCHEME=d:/Develop/MzScheme MZSCHEME_VER=209_000 + MZSCHEME_DLLS=c:/Temp DYNAMIC_MZSCHEME=no + +After a successful build, these dlls can be freely removed, leaving them in +%WINDOWS%\System32 only. + + + +9. Building with Lua support +============================ + +Vim with Lua support can be built with either MSVC or MinGW (or maybe Cygwin). +You can use binaries from LuaBinaries: http://luabinaries.sourceforge.net/ +This also applies to when you get a Vim executable and don't build yourself, +do the part up to "Build". + +1) Download and install LuaBinaries + +Go to the Download page of LuaBinaries: + http://luabinaries.sourceforge.net/download.html + +Download lua-X.Y.Z_Win32_dllw4_lib.zip for x86 or +lua-X.Y.Z_Win64_dllw4_lib.zip for x64. You can use them both for MSVC and +MinGW. + +Unpack it to a working directory. E.g. C:\projects\lua53. +Lua's header files will be installed under the include directory. + +Copy luaXY.dll to your Windows system directory. The system directory depends +on your Windows bitness and Vim bitness: + 32-bit Vim on 32-bit Windows: C:\Windows\System32 + 32-bit Vim on 64-bit Windows: C:\Windows\SysWOW64 + 64-bit Vim on 64-bit Windows: C:\Windows\System32 + +Or another option is copying luaXY.dll to the directory where gvim.exe +(or vim.exe) is. + + +2) Build + +You need to set LUA, DYNAMIC_LUA and LUA_VER. + + LUA: Where Lua's header files are installed. E.g. C:\projects\lua53. + DYNAMIC_LUA: Whether dynamic linking is used. Set to yes. + LUA_VER: Lua version. E.g. 53 for Lua 5.3.X. + +E.g. When using MSVC (as one line): + + nmake -f Make_mvc.mak + LUA=C:\projects\lua53 DYNAMIC_LUA=yes LUA_VER=53 + +Or when using MinGW (as one line): + + mingw32-make -f Make_ming.mak + LUA=C:/projects/lua53 DYNAMIC_LUA=yes LUA_VER=53 + + +Or when using Cygwin (as one line) (untested): + + make -f Make_cyg.mak + LUA=/cygdrive/c/projects/lua53 DYNAMIC_LUA=yes LUA_VER=53 + + +10. Building with Perl support +============================== + +Vim with Perl support can be built with either MSVC or MinGW (or Cygwin). +You can use binaries from ActiveState (ActivePerl) or Strawberry Perl. + + http://www.activestate.com/activeperl + http://strawberryperl.com/ + +When building, you need to set the following variables: + + PERL: Where perl is installed. E.g. C:\Perl, C:\Strawberry\perl + DYNAMIC_PERL: Whether dynamic linking is used. Usually, set to yes. + PERL_VER: Perl version. E.g. 522 for Perl 5.22.X. + +E.g. When using MSVC (as one line): + + nmake -f Make_mvc.mak + PERL=C:\Perl DYNAMIC_PERL=yes PERL_VER=522 + +Or when using MinGW (as one line): + + mingw32-make -f Make_ming.mak + PERL=C:/Perl DYNAMIC_PERL=yes PERL_VER=522 + + +11. Building with Ruby support +============================== + +Vim with Ruby support can be built with either MSVC or MinGW (or Cygwin). +Ruby doesn't provide the official Windows binaries. The most widely used +Windows binaries might be RubyInstaller. Currently Ruby 2.4 is recommended. + + http://rubyinstaller.org/ + +If you use MinGW you can easily build with RubyInstaller, but if you use MSVC +you need some tricks described below. +(Another binary distribution is ActiveScriptRuby: + http://www.artonx.org/data/asr/) + +When building, you need to set the following variables at least: + + RUBY: Where ruby is installed. E.g. C:\Ruby24 + DYNAMIC_RUBY: Whether dynamic linking is used. Usually, set to yes. + RUBY_VER: Ruby version. E.g. 24 for Ruby 2.4.X. + RUBY_API_VER_LONG: Ruby API version in a long format. + E.g. 2.4.0 for Ruby 2.4.X. + +Ruby version vs. Ruby API version: + + Ruby ver. | Ruby API ver. + ========================= + 1.9.[1-3] | 1.9.1 + 2.0.0 | 2.0.0 + 2.X.Y | 2.X.0 + +(Ruby 1.9.0 is excluded from the table because it is an unstable version.) + + +A) Using MSVC + +If you want to link with ruby, normally you must use the same compiler as +which was used to build the ruby binary. RubyInstaller is built with MinGW, +so normally you cannot use MSVC for building Vim if you want to link with +RubyInstaller. If you use a different compiler, there are mainly two problems: +config.h and Ruby's DLL name. Here are the steps for working around them: + + 1) Download and Install RubyInstaller. + You can install RubyInstaller with the default options and directory. + E.g.: + C:\Ruby24 (32-bit) or C:\Ruby24-x64 (64-bit) + + Ruby 2.4.X is used in this example. + + 2) Download Ruby 2.4.X's source code and generate config.h: + + cd C:\projects + git clone https://github.com/ruby/ruby.git -b ruby_2_4 + cd ruby + win32\configure.bat + nmake .config.h.time + + Note that ruby_2_4 is the branch name for Ruby 2.4.X's source code. + There is no need to build whole Ruby, just config.h is needed. + If you use 32-bit MSVC 2015, the config.h is generated in the + .ext\include\i386-mswin32_140 directory. + If you use 64-bit MSVC 2015, the config.h is generated in the + .ext\include\x64-mswin64_140 directory. + + 3) Install the generated config.h. + + For 32-bit version: + + xcopy /s .ext\include C:\Ruby24\include\ruby-2.4.0 + + For 64-bit version: + + xcopy /s .ext\include C:\Ruby24-x64\include\ruby-2.4.0 + + Note that 2.4.0 is Ruby API version of Ruby 2.4.X. + You may need to close the console and reopen it to pick up the new $PATH. + + 4) Build Vim. Note that you need to adjust some variables (as one line): + + For 32-bit version: + + nmake -f Make_mvc.mak + RUBY=C:\Ruby24 DYNAMIC_RUBY=yes RUBY_VER=24 RUBY_API_VER_LONG=2.4.0 + RUBY_MSVCRT_NAME=msvcrt + WINVER=0x601 + + For 64-bit version, replace RUBY=C:\Ruby24 with RUBY=C:\Ruby24-x64. + + If you set WINVER explicitly, it must be set to >=0x500, when building + with Ruby 2.1 or later. (Default is 0x601.) + When using this trick, you also need to set RUBY_MSVCRT_NAME to msvcrt + which is used for the Ruby's DLL name. + +B) Using MinGW + +Using MinGW is easier than using MSVC when linking with RubyInstaller. +After you install RubyInstaller, just type this (as one line): + + mingw32-make -f Make_ming.mak + RUBY=C:/Ruby24 DYNAMIC_RUBY=yes RUBY_VER=24 RUBY_API_VER_LONG=2.4.0 + WINVER=0x601 + +For 64-bit version, replace RUBY=C:/Ruby24 with RUBY=C:/Ruby24-x64. +If you set WINVER explicitly, it must be set to >=0x500, when building with +Ruby 2.1 or later. (Default is 0x601.) + + + +12. Building with Tcl support +============================= + +Vim with Tcl support can be built with either MSVC or MinGW (or Cygwin). +You can use binaries from ActiveState (ActiveTcl). + + http://www.activestate.com/activetcl + +Alternatively, you can use the binaries provided by IronTcl from + + https://www.irontcl.com/ + +They might lack behind the latest version a bit, but should provide 64bit +and 32bit versions even if ActiveTcl does not provide them anymore. + +For building with MSVC 2015 use version 8.6.6 or later. +When building, you need to set the following variables: + + TCL: Where tcl is installed. E.g. C:\Tcl86 + DYNAMIC_TCL: Whether dynamic linking is used. Usually, set to yes. + TCL_VER: Tcl version in a short format. E.g. 86 for Tcl 8.6.X. + TCL_VER_LONG: Tcl version in a long format. E.g. 8.6 for Tcl 8.6.X. + +Sometimes the Tcl dll name changes. E.g. ActiveTcl 8.6.4 comes with tcl86.dll, +but ActiveTcl 8.6.6 comes with tcl86t.dll. You can set the dll name by setting +the TCL_DLL variable: + TCL_DLL=tcl86t.dll + +E.g. When using MSVC (as one line): + + nmake -f Make_mvc.mak + TCL=C:\Tcl86 DYNAMIC_TCL=yes TCL_VER=86 TCL_VER_LONG=8.6 + +Or when using MinGW (as one line): + + mingw32-make -f Make_ming.mak + TCL=C:/Tcl86 DYNAMIC_TCL=yes TCL_VER=86 TCL_VER_LONG=8.6 + + +13. Building with DirectX (DirectWrite) support +=============================================== + +Vim with DirectX (DirectWrite) support can be built with either MSVC or MinGW. +This requires dwrite_2.h and some other header files which come with Windows +SDK 8.1 or later (or MinGW-w64), if you want to enable color emoji support. +This also requires MBYTE=yes which is enabled by default. + +A) Using MSVC + +If you use MSVC 2013 or later, Windows SDK 8.1 or later is used by default. +You just need to specify DIRECTX=yes: + + nmake -f Make_mvc.mak DIRECTX=yes + +If you use MSVC 2012 or earlier, the required header files are not available +by default. However, you can use the header files from newer SDKs with older +compilers. E.g.: + + set "INCLUDE=%INCLUDE%;C:\Program Files (x86)\Windows Kits\8.1\Include\um" + nmake -f Make_mvc.mak DIRECTX=yes + +If you don't need color emoji support, only dwrite.h is required. You can use +older compilers (e.g. VC2010) without Windows SDK 8.1. E.g.: + + nmake -f Make_mvc.mak DIRECTX=yes COLOR_EMOJI=no + +B) Using MinGW-w64 + +Just set DIRECTX to yes: + + mingw32-make -f Make_ming.mak DIRECTX=yes + + +14. Building with libsodium support +=================================== + +For better encryption support, you can build Vim with libsodium. + +A) Using MSVC + +You can download the latest libsodium library from here: + https://download.libsodium.org/libsodium/releases/ + +At this moment, libsodium-1.0.18-stable-msvc.zip is the latest package. +Unpack it to anywhere you like, and specify the path to the SODIUM option: + + nmake -f Make_mvc.mak SODIUM=C:/path/to/libsodium + (libsodium.dll will be used as the libsodium DLL name.) + +B) Using MinGW + +If you use msys2, you can install the libsodium package by pacman (or pacboy): + + $ pacman -S mingw-w64-x86_64-libsodium # for 64-bit Vim + $ pacman -S mingw-w64-i686-libsodium # for 32-bit Vim + $ pacboy -S libsodium:m # for both 32-bit and 64-bit Vim + +Then set SODIUM to yes: + + mingw32-make -f Make_ming.mak SODIUM=yes + (libsodium-23.dll will be used as the libsodium DLL name.) + +Or you can set the path to libsodium explicitly: + + mingw32-make -f Make_ming.mak SODIUM=C:/path/to/libsodium + (libsodium.dll will be used as the libsodium DLL name.) + + +15. Windows 3.1x +================ + +The Windows 3.1x support was removed in patch 7.4.1364. + + +16. MS-DOS +========== + +The MS-DOS support was removed in patch 7.4.1399. Only very old Vim versions +work on MS-DOS because of the limited amount of memory available. + + +17. Installing after building from sources +========================================== + +[provided by Michael Soyka, updated by Ken Takata] + +After you've built the Vim binaries as described above, you're ready to +install Vim on your system. However, if you've obtained the Vim sources +using Git, Mercurial or by downloading them as a unix tar file, you must +first create a "vim90" directory. If you instead downloaded the sources as +zip files, you can skip this setup as the zip archives already have the +correct directory structure. + + A. Create a Vim "runtime" subdirectory named "vim90" + ----------------------------------------------------- + If you obtained your Vim sources as zip files, you can skip this step. + Otherwise, continue reading. + + Go to the directory that contains the Vim "src" and "runtime" + directories and create a new subdirectory named "vim90". + + Copy the "runtime" files into "vim90": + copy runtime\* vim90 + xcopy /s runtime\* vim90 + + B. Copy the new binaries into the "vim90" directory + ---------------------------------------------------- + Regardless of how you installed the Vim sources, you need to copy the + new binaries you created above into "vim90": + + copy src\*.exe vim90 + copy src\tee\tee.exe vim90 + copy src\xxd\xxd.exe vim90 + + To install the "Edit with Vim" popup menu, you need both 32-bit and 64-bit + versions of gvimext.dll. They should be copied to "vim90\GvimExt32" and + "vim90\GvimExt64" respectively. + First, build the 32-bit version, then: + + mkdir vim90\GvimExt32 + copy src\GvimExt\gvimext.dll vim90\GvimExt32 + + Next, clean the 32-bit version and build the 64-bit version, then: + + mkdir vim90\GvimExt64 + copy src\GvimExt\gvimext.dll vim90\GvimExt64 + + C. Copy gettext and iconv DLLs into the "vim90" directory + ---------------------------------------------------------- + Get gettext and iconv DLLs from the following site: + https://github.com/mlocati/gettext-iconv-windows/releases + Both 64- and 32-bit versions are needed. + Download the files gettextX.X.X.X-iconvX.XX-shared-{32,64}.zip, extract + DLLs and place them as follows: + + vim90\ + | libintl-8.dll + | libiconv-2.dll + | libgcc_s_sjlj-1.dll (only for 32-bit) + | + + GvimExt32\ + | libintl-8.dll + | libiconv-2.dll + | libgcc_s_sjlj-1.dll + | + ` GvimExt64\ + libintl-8.dll + libiconv-2.dll + + The DLLs in the "vim90" should be the same bitness with the (g)vim.exe. + + D. Move the "vim90" directory into the Vim installation subdirectory + --------------------------------------------------------------------- + Move the "vim90" subdirectory into the subdirectory where you want Vim + to be installed. Typically, this subdirectory will be named "vim". + If you already have a "vim90" subdirectory in "vim", delete it first + by running its uninstall.exe program. + + E. Install Vim + --------------- + "cd" to your Vim installation subdirectory "vim\vim90" and run the + "install.exe" program. It will ask you a number of questions about + how you would like to have your Vim setup. Among these are: + - You can tell it to write a "_vimrc" file with your preferences in the + parent directory. + - It can also install an "Edit with Vim" entry in the Windows Explorer + popup menu. + - You can have it create batch files, so that you can run Vim from the + console or in a shell. You can select one of the directories in your + PATH or add the directory to PATH using the Windows Control Panel. + - Create entries for Vim on the desktop and in the Start menu. + +Happy Vimming! diff --git a/src/INSTALLvms.txt b/src/INSTALLvms.txt new file mode 100644 index 0000000..c235151 --- /dev/null +++ b/src/INSTALLvms.txt @@ -0,0 +1,390 @@ +INSTALLvms.txt - Installation of Vim on OpenVMS + +Maintainer: Zoltan Arpadffy +Last change: 2008 Jan 06 + +This file contains instructions for compiling Vim on Openvms. +If you already have an executable version of Vim, you don't need this. + +If you skip settings described here, then you will get the default Vim +behavior as it is documented, which should be fine for most users. + +The file "feature.h" can be edited to match your preferences, but this file +does not describe possibilities hidden in feature.h acrobatics, however +parameters from MAKE_VMS.MMS actively use and set up parameters in relation +with feature.h + +More information and case analysis you can find in os_vms.txt +([runtime.doc]os_vms.txt or :help vms from vim prompt) + +Contents: +1. Download files +2. Configuration +3. Compilation DECC +4. Compilation VAXC +5. CTAGS, XXD +6. Deployment +7. GTK and other features +8. Notes +9. Authors + +---------------------------------------------------------------------------- +1. Download files + +1.1. Visit the Vim ftp site (see ftp://ftp.vim.org/pub/vim/MIRRORS) + and obtain the following three files: + + unix/vim-X.X-src.tar.gz + unix/vim-X.X-rt.tar.gz + extra/vim-X.X-extra.tar.gz + + where X.X is the version number. + +1.2. Expand the three archives. + +1.3. Apply patches if they exist. (Patch files are found in the ftp + site in the "patches" directory.) + +1.4. You will need either the DECSET mms utility or the freely available clone + of it called mmk (VMS has no make utility in the standard distribution). + You can download mmk from http://www.openvms.digital.com/freeware/MMK/ + +1.5. If you want to have Perl, Python or Tcl support in Vim you will need VMS + distributions for them as well. + +1.6 If you want to have GTK executable, you need to have properly installed + GTK libraries. + +NOTE: procedure in chapter 1 describes source code preparation from multi OS +code, however it is available OpenVMS optimized (and tested) source code from: +ftp://ftp.polarhome.com/pub/vim/source/vms/ +(http://www.polarhome.com/vim/files/source/vms/) + +Current OpenVMS source code as .zip or .tar.gz file is possible to download +from CVS mirror ftp://ftp.polarhome.com/pub/cvs/SOURCE/ +(http://www.polarhome.com/cvs/SOURCE/) + +2. Configuration + +2.1. Edit vim-X.X/src/feature.h for your preference. (You can skip + this, then you will get the default behavior as is documented, + which should be fine for most people.) + + For example, if you want to add the MULTI_BYTE feature, turn on + #define MULTI_BYTE + +2.2 Edit vim-X.X/src/Make_vms.mms to customize your Vim. Options are: + + Parameter name : MODEL + Description : Build model selection + Options: : TINY - No optional features enabled + NORMAL - A default selection of features enabled + (OpenVMS default) + HUGE - All possible features enabled. + Uncommented - will default to NORMAL + Default : MODEL = NORMAL + + Parameter name : GUI + Description : GUI or terminal mode executable + Options: : YES - GUI executable + Uncommented - char only + Default : GUI = YES + + Parameter name : GTK + Description : Enable GTK in GUI mode. + It enables features as toolbar etc. + Options: : YES - GTK executable + Uncommented - without GTK + Default : Uncommented + + Parameter name : XPM + Description : Enable XPM libraries in GUI/Motif mode. + It enables features as toolbar etc. + Options: : YES - GUI executable + Uncommented - without XPM + Default : Uncommented + + Parameter name : DECC + Description : Compiler selection + Options: : YES - DECC compiler + Uncommented - VAXC compiler + Default : DECC = YES + + Parameter name : CCVER + Description : Compiler version with :ver command + Options: : YES - Compiler version info will be added + Uncommented - will not be added + Default : CCVER = YES + + Parameter name : DEBUG + Description : Building a debug version + Options: : YES - debug version will be built + Uncommented - building normal executable + Default : Uncommented + + Parameter name : VIM_TCL + Description : Add Tcl support + Options: : YES - Build with support + Uncommented - build without support. + Default : Uncommented + + Parameter name : VIM_PERL + Description : Add Perl support + Options: : YES - Build with support + Uncommented - build without support. + Default : Uncommented + + Parameter name : VIM_PYTHON + Description : Add Python support + Options: : YES - Build with support + Uncommented - build without support. + Default : Uncommented + + Parameter name : VIM_XIM + Description : X Input Method. For entering special languages + like Chinese and Japanese. Please define just + one: VIM_XIM or VIM_HANGULIN + Options: : YES - Build with support + Uncommented - build without support. + Default : Uncommented + + Parameter name : VIM_HANGULIN + Description : Internal Hangul input method. GUI only. + Please define just one: VIM_XIM or VIM_HANGULIN + Options: : YES - Build with support + Uncommented - build without support. + Default : Uncommented + + Parameter name : VIM_TAG_ANYWHITE + Description : Allow any white space to separate the fields in a + tags file + When not defined, only a TAB is allowed. + Options: : YES - Build with support + Uncommented - build without support. + Default : Uncommented + + You can edit the *_INC and *_LIB qualifiers, but it is really + not recommended for beginners. + +3. Compilation DECC + +3.1. If you have MSS on your system, the command + + mms /descrip=Make_vms.mms + + will start building your own customized version of Vim. + The adequate command for mmk is: + + mmk /descrip=Make_vms.mms + + NOTE: Because of empty /auto/config.h (needed for Unix configure) build + will fail with very strange messages. Therefore before building, it is + recommended to make one clean up, to prepare everything for OpenVMS + development. The command is: + + mms /descrip=Make_vms.mms clean + +4. Compilation VAXC + +4.1. VAXC compiler is not fully ANSI C compatible in pre-processor directives + semantics, therefore you have to use a converter program what will do the + lion part of the job. + + @os_vms_fix.com *.c *.h <.proto>*.pro + + more information can be found in os_vms_fix.com file itself. + + NOTE: even if os_vms_fix.com will fix all pre-processor directives it will + leave single (long) line directives. You have to fix them manually. + Known problematic files are option.h and option.c + +4.2. After the conversion you can continue building as it has been described + above. + +5. CTAGS, XXD + +5.1. MMS_VIM.EXE is building together with VIM.EXE, but for CTAGS.EXE and + XXD.EXE you should change to subdirectory <.CTAGS> or <.XXD> and build + them separately. + +5.2. In these directories you can find one make file for VMS as well. + Please read the detailed build instructions in the related *.MMS file. + +6. Deployment + +6.1. Copy over all executables to the deployment directory. + +6.2. Vim uses a special directory structure to hold the document and runtime + files: + + vim (or wherever) + |-- doc + |-- syntax + vimrc (system rc files) + gvimrc + +6.3 Define logicals VIM + + define/nolog VIM device:[leading-path-here.vim] + + to get vim.exe to find its document, filetype, and syntax files. + + Now, if you are lucky you should have one own built, customized and + working Vim. + +7. GTK and other features + +7.1 General notes + + To be able to build external GUI or language support you have to enable + related feature in MAKE_VMS.MMS file. Usually it needs some extra tuning + around include files, shared libraries etc. + + Please note, that leading "," are valuable for MMS/MMK syntax. + + MAKE_VMS.MMS uses defines as described below: + +7.1.1 feature_DEF = ,"SOME_FEATURE" + + Submits definition to compiler preprocessor to enable code blocks + defined with + #ifdef SOME_FEATURE + {some code here} + #endif + + Example: TCL_DEF = ,"FEAT_TCL" + + +7.1.2 feature_SRC = code1.c code2.c + + Defines source code related with particular feature. + Example: TCL_SRC = if_tcl.c + +7.1.3 feature_OBJ = code1.obj code2.obj + + Lists objects created from source codes listed in feature_SRC + Example: PERL_OBJ = if_perlsfio.obj if_perl.obj + +7.1.4 feature_LIB = ,OS_VMS_TCL.OPT/OPT + + Defines the libraries that have to be used for build. + If it is an OPT file then MAKE_VMS.MMS creates OPT files + in gen_feature procedure. + + Example: + PERL_LIB = ,OS_VMS_PERL.OPT/OPT + +.IFDEF VIM_PERL +perl_env : + -@ write sys$output "creating OS_VMS_PERL.OPT file." + -@ open/write opt_file OS_VMS_PERL.OPT + -@ write opt_file "PERLSHR /share" + -@ close opt_file +.ELSE +perl_env : + -@ ! +.ENDIF + + +7.1.5 feature_INC = ,dka0:[tcl80.generic] + + Defines the directory where the necessary include files are. + Example: TCL_INC = ,dka0:[tcl80.generic] + +7.2 GTK + + To build VIM with GTK you have to install GTK on your OpenVMS. + So far it works just on Alpha and IA64. More information at: + http://www.openvms.compaq.com/openvms/products/ips/gtk.html + + You also need the OpenVMS Porting Library: + http://www.openvms.compaq.com/openvms/products/ips/porting.html + + Source code for GTK and porting library that is used to build + VMS executables at polarhome.com are at + http://www.polarhome.com/vim/files/source/vms/ + + Enable GTK in make_vms.mms file with GTK = YES + Define GTK_ROOT that points to your GTK root directory. + + You will need to edit GTKDIR variable in order to point + to GTK header files and libraries. + + GTK_DIR = ALPHA$DKA0:[GTK128.] + + ".]" at the end is very important. + + Build it as normally. + + Used shareable images are: + gtk_root:[glib]libglib.exe /share,- + gtk_root:[glib.gmodule]libgmodule.exe /share,- + gtk_root:[gtk.gdk]libgdk.exe /share,- + gtk_root:[gtk.gtk]libgtk.exe /share + + During runtime it is suggested to have all these files installed and + copied to SYS$LIBRARY: to be able to use it without problems. + Also VMS_JACKETS.EXE from OpenVMS Porting Library. + + Please note, that GTK uses /name=(as_is,short)/float=ieee/ieee=denorm + compiler directives that is not compatible with "standard" VMS usage, + therefore other external features might fail as PERL, PYTHON and TCL + support. + +7.3 PERL + + You have to install OpenVMS perl package from: + http://www.openvms.compaq.com/openvms/products/ips/apache/csws_perl_relnotes.html or build on your own from sources downloaded from http://www.perl.org + + You need defined PERLSHR logical that points to PERL shareable image + (or you can just copy over to SYS$LIBRARY:) + + Enable Perl feature at make_vms.mms with VIM_PERL = YES + + Edit PERL_INC = to point to perl includes directory where is extern.h + + Build as usual. + +7.4 PYTHON + + You have to install an OpenVMS python package. + Set up the normal Python work environment. + + You have to have defined PYTHON_INCLUDE and PYTHON_OLB logicals. + PYTHON_INCLUDE should point to Python include files where for ex: + python.h is located. + Enable Python feature at make_vms.mms with VIM_PYTHON = YES + + Build as usual. + +7.5 TCL + + You have to install an OpenVMS TCL package. + Set up the normal TCL work environment. + + You have to have defined TCLSHR logical that points to shareable image. + + Enable TCL feature at make_vms.mms with VIM_TCL = YES + + Edit TCL_INC = to point to TCL includes directory where is tcl.h + + Build as usual. + +8. Notes + +8.1. New Compaq C compiler + + If you are using Compaq C compiler V6.2 or newer, informational messages + of the type QUESTCOMPARE will be displayed. You should ignore those + messages ; they are generated only because some test comparisons are done + with variables which type vary depending on the OS. Under VMS, those are + "unsigned" and the compiler issue a message whenever the comparison is + done with '<=' to 0. However, the code is correct and will behave as + expected. + ( Jerome Lauret Vim 6.0n ) + NOTE: from version 6.0ad Vim code has been reviewed and these warnings + have been corrected. + +9. Authors + + Initial version, 2000 Jul 19, Zoltan Arpadffy diff --git a/src/INSTALLx.txt b/src/INSTALLx.txt new file mode 100644 index 0000000..c120a1d --- /dev/null +++ b/src/INSTALLx.txt @@ -0,0 +1,156 @@ +INSTALLx.txt - cross-compiling Vim on Unix + +Content: + 1. Introduction + 2. Necessary arguments for "configure" + 3. Necessary environment variables for "configure" + 4. Example + + +1. INTRODUCTION +=============== + +This document discusses cross-compiling VIM on Unix-like systems. We assume +you are already familiar with cross-compiling and have a working cross-compile +environment with at least the following components: + + * a cross-compiler + * a libc to link against + * ncurses library to link against + +Discussing how to set up a cross-compile environment would go beyond the scope +of this document. See http://www.kegel.com/crosstool/ for more information and +a script that aids in setting up such an environment. + + +The problem is that "configure" needs to compile and run small test programs +to check for certain features. Running these test programs can't be done when +cross-compiling so we need to pass the results these checks would produce via +environment variables. See the list of variables and the examples at the end of +this document. + + +2. NECESSARY ARGUMENTS FOR "configure" +====================================== + +You need to set the following "configure" command line switches: + +--build=... : + The build system (i.e. the platform name of the system you compile on + right now). + For example, "i586-linux". + +--host=... : + The system on which VIM will be run. Quite often this the name of your + cross-compiler without the "-gcc". + For example, "powerpc-603-linux-gnu". + +--target=... : + Only relevant for compiling compilers. Set this to the same value as + --host. + +--with-tlib=... : + Which terminal library to use. + For example, "ncurses". + + +3. NECESSARY ENVIRONMENT VARIABLES FOR "configure" +================================================== + +Additionally to the variables listed here you might want to set the CPPFLAGS +environment variable to enable optimization for your target system (e.g. +"CPPFLAGS=-march=arm5te"). + +The following variables need to be set: + +ac_cv_sizeof_int: + The size of an "int" C type in bytes. Should be "4" on all 32bit + machines. + +vi_cv_path_python_conf: + If Python support is enabled, set this variable to the path for + Python's library implementation. This is a path like + "/usr/lib/pythonX.Y/config" (the directory contains a file + "config.c"). + +vi_cv_var_python_epfx: + If Python support is enabled, set this variable to the execution + prefix of your Python interpreter (that is, where it thinks it is + running). + This is the output of the following Python script: + import sys; print sys.exec_prefix + +vi_cv_var_python_pfx: + If Python support is enabled, set this variable to the prefix of your + Python interpreter (that is, where it was installed). + This is the output of the following Python script: + import sys; print sys.prefix + +vi_cv_var_python_version: + If Python support is enabled, set this variable to the version of the + Python interpreter that will be used. + This is the output of the following Python script: + import sys; print sys.version[:3] + +vim_cv_bcopy_handles_overlap: + Whether the "memmove" C library call is able to copy overlapping + memory regions. Set to "yes" if it does or "no" if it does not. + You only need to set this if vim_cv_memmove_handles_overlap is set + to "no". + +vim_cv_getcwd_broken: + Whether the "getcwd" C library call is broken. Set to "yes" if you + know that "getcwd" is implemented as 'system("sh -c pwd")', set to + "no" otherwise. + +vim_cv_memcpy_handles_overlap: + Whether the "memcpy" C library call is able to copy overlapping + memory regions. Set to "yes" if it does or "no" if it does not. + You only need to set this if both vim_cv_memmove_handles_overlap + and vim_cv_bcopy_handles_overlap are set to "no". + +vim_cv_memmove_handles_overlap: + Whether the "memmove" C library call is able to copy overlapping + memory regions. Set to "yes" if it does or "no" if it does not. + +vim_cv_stat_ignores_slash: + Whether the "stat" C library call ignores trailing slashes in the path + name. Set to "yes" if it ignores them or "no" if it does not ignore + them. + +vim_cv_tgetent: + Whether the "tgetent" terminal library call returns a zero or non-zero + value when it encounters an unknown terminal. Set to either the string + "zero" or "non-zero", corresponding. + +vim_cv_terminfo: + Whether the environment has terminfo support. Set to "yes" if so, + otherwise set to "no". + +vim_cv_toupper_broken: + Whether the "toupper" C library function works correctly. Set to "yes" + if you know it's broken, otherwise set to "no". + + +4. EXAMPLE: +=========== + +Assuming the target system string is "armeb-xscale-linux-gnu" (a Intel XScale +system) with glibc and ncurses, the call to configure would look like this: + +ac_cv_sizeof_int=4 \ +vim_cv_getcwd_broken=no \ +vim_cv_memmove_handles_overlap=yes \ +vim_cv_stat_ignores_slash=yes \ +vim_cv_tgetent=zero \ +vim_cv_terminfo=yes \ +vim_cv_toupper_broken=no \ +./configure \ + --build=i586-linux \ + --host=armeb-xscale-linux-gnu \ + --target=armeb-xscale-linux-gnu \ + --with-tlib=ncurses + + + +Written 2007 by Marc Haisenko for the VIM project. diff --git a/src/Make_all.mak b/src/Make_all.mak new file mode 100644 index 0000000..6a6d2fe --- /dev/null +++ b/src/Make_all.mak @@ -0,0 +1,16 @@ +# +# Common Makefile, defines the list of tests to run and other things. +# + +# Argument for running ctags. +TAGS_FILES = \ + *.c \ + *.cc \ + *.cpp \ + *.h \ + auto/*.c \ + libvterm/src/*.c \ + libvterm/src/*.h \ + libvterm/include/*.h \ + xdiff/*.c \ + xdiff/*.h diff --git a/src/Make_ami.mak b/src/Make_ami.mak new file mode 100644 index 0000000..9e9ebe3 --- /dev/null +++ b/src/Make_ami.mak @@ -0,0 +1,202 @@ +# +# Makefile for AROS, AmigaOS4 and MorphOS. +# +BIN = vim +CC ?= gcc +LD = $(CC) +UNM ?= $(shell uname) +DEBUG ?= no +BUILD ?= huge +CFLAGS = -c -O3 + +# Common compiler flags +CFLAGS += \ + -DNO_ARP \ + -DUSE_TMPNAM \ + -DHAVE_STDARG_H \ + -DHAVE_TGETENT \ + -DHAVE_TERMCAP \ + -DNEW_SHELLSIZE \ + -I proto \ + -Wno-attributes \ + -Wextra + +# Vim 'huge' build +ifeq ($(BUILD),huge) +CFLAGS += \ + -DFEAT_BROWSE \ + -DFEAT_MOUSE \ + -DFEAT_HUGE +else + +# Vim 'normal' build +ifeq ($(BUILD),normal) +CFLAGS +=\ + -DFEAT_BROWSE \ + -DFEAT_MOUSE \ + -DFEAT_NORMAL +else + +# Vim 'small' build - now an alias for 'tiny' +ifeq ($(BUILD),small) +CFLAGS += -DFEAT_TINY +else + +# Vim 'tiny' build +ifeq ($(BUILD),tiny) +CFLAGS += -DFEAT_TINY +endif +endif +endif +endif +endif + +# OS specific compiler flags +ifeq ($(UNM),AmigaOS) +LDFLAGS = -mcrt=clib2 -lauto -lm -lnet +CFLAGS += -DHAVE_FSYNC -D__USE_INLINE__ -mcrt=clib2 +else +ifeq ($(UNM),AROS) +LDFLAGS = -DHAVE_FSYNC -ldebug +else +ifeq ($(UNM),MorphOS) +CFLAGS += -noixemul +LDFLAGS = -ldebug -lm -noixemul +endif +endif +endif + +# Patch level used for Amiga style version string +ifdef PATCHLEVEL +CFLAGS += -DPATCHLEVEL=\"$(PATCHLEVEL)\" +endif + +# Common sources +SRC += \ + alloc.c \ + arabic.c \ + arglist.c \ + autocmd.c \ + beval.c \ + blob.c \ + blowfish.c \ + buffer.c \ + bufwrite.c \ + change.c \ + charset.c \ + cindent.c \ + clientserver.c \ + clipboard.c \ + cmdhist.c \ + cmdexpand.c \ + crypt.c \ + crypt_zip.c \ + debugger.c \ + dict.c \ + diff.c \ + digraph.c \ + drawline.c \ + drawscreen.c \ + edit.c \ + eval.c \ + evalbuffer.c \ + evalfunc.c \ + evalvars.c \ + evalwindow.c \ + ex_cmds.c \ + ex_cmds2.c \ + ex_docmd.c \ + ex_eval.c \ + ex_getln.c \ + fileio.c \ + filepath.c \ + findfile.c \ + float.c \ + fold.c \ + getchar.c \ + hardcopy.c \ + hashtab.c \ + help.c \ + highlight.c \ + if_cscope.c \ + indent.c \ + insexpand.c \ + json.c \ + list.c \ + locale.c \ + logfile.c \ + main.c \ + mark.c \ + map.c \ + match.c \ + mbyte.c \ + memfile.c \ + memline.c \ + menu.c \ + message.c \ + misc1.c \ + misc2.c \ + mouse.c \ + move.c \ + normal.c \ + ops.c \ + option.c \ + optionstr.c \ + os_amiga.c \ + popupmenu.c \ + popupwin.c \ + quickfix.c \ + regexp.c \ + register.c \ + screen.c \ + scriptfile.c \ + search.c \ + session.c \ + sha256.c \ + sign.c \ + spell.c \ + spellfile.c \ + spellsuggest.c \ + strings.c \ + syntax.c \ + tag.c \ + term.c \ + termlib.c \ + testing.c \ + textformat.c \ + textobject.c \ + textprop.c \ + time.c \ + typval.c \ + ui.c \ + undo.c \ + usercmd.c \ + userfunc.c \ + version.c \ + viminfo.c \ + vim9class.c \ + vim9cmds.c \ + vim9compile.c \ + vim9execute.c \ + vim9expr.c \ + vim9instr.c \ + vim9script.c \ + vim9type.c \ + window.c \ + xdiff/xdiffi.c \ + xdiff/xemit.c \ + xdiff/xhistogram.c \ + xdiff/xpatience.c \ + xdiff/xprepare.c \ + xdiff/xutils.c + +OBJ = $(SRC:.c=.o) + +# Build everything - Ignoring header dependencies. +$(BIN): $(OBJ) + ${LD} -o $(BIN) $(OBJ) $(LDFLAGS) + +# Clean up +.PHONY: clean +clean: + $(RM) -fv $(OBJ) $(BIN) diff --git a/src/Make_cyg.mak b/src/Make_cyg.mak new file mode 100644 index 0000000..8bb2b72 --- /dev/null +++ b/src/Make_cyg.mak @@ -0,0 +1,53 @@ +# +# Makefile for VIM on Win32, using MinGW cross compiler on Cygwin +# +# Also read INSTALLpc.txt! +# +# This compiles Vim as a Windows application. If you want Vim to run as a +# Cygwin application use the Makefile (just like on Unix). +# +# The old Make_cyg.mak (maintained by Dan Sharp et al.) was merged into +# Make_cyg_ming.mak. Note: USEDLL option was removed. +# This file contains Cygwin specific settings. Common settings are contained +# in Make_cyg_ming.mak. +# +# Last updated by Ken Takata. +# Last Change: 2014 Oct 21 + + +# uncomment 'PERL' if you want a perl-enabled version +#PERL=/cygdrive/c/perl + +# uncomment 'LUA' if you want a Lua-enabled version +#LUA=/cygdrive/c/lua + +# uncomment 'MZSCHEME' if you want a MzScheme-enabled version +#MZSCHEME=/cygdrive/d/plt + +# uncomment 'PYTHON' if you want a python-enabled version +#PYTHON=/cygdrive/c/python20 + +# uncomment 'PYTHON3' if you want a python3-enabled version +#PYTHON3=/cygdrive/c/python31 + +# uncomment 'TCL' if you want a Tcl-enabled version +#TCL=/cygdrive/c/tcl + +# uncomment 'RUBY' if you want a Ruby-enabled version +#RUBY=/cygdribe/c/ruby + + +# Use MinGW-w64 cross compiler. +# There are two MinGW-w64 packages in Cygwin: +# 32-bit: mingw64-i686-gcc-g++ +# 64-bit: mingw64-x86_64-gcc-g++ +# You may also need to set 'ARCH' in Make_cyg_ming.mak. +CROSS_COMPILE = i686-w64-mingw32- +#CROSS_COMPILE = x86_64-w64-mingw32- + + +# Do not change this. +UNDER_CYGWIN = yes +include Make_cyg_ming.mak + +# vim: set noet sw=8 ts=8 sts=0 wm=0 tw=0: diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak new file mode 100644 index 0000000..4261256 --- /dev/null +++ b/src/Make_cyg_ming.mak @@ -0,0 +1,1383 @@ +# Makefile for VIM on Win32 (Cygwin and MinGW) +# +# This file contains common part for Cygwin and MinGW and it is included +# from Make_cyg.mak and Make_ming.mak. +# +# Info at http://www.mingw.org +# Alternative x86 and 64-builds: http://mingw-w64.sourceforge.net +# Also requires GNU make, which you can download from the same sites. +# Get missing libraries from http://gnuwin32.sf.net. +# +# Tested on Win32 NT 4 and Win95. +# +# To make everything, just 'make -f Make_ming.mak'. +# To make just e.g. gvim.exe, 'make -f Make_ming.mak gvim.exe'. +# After a run, you can 'make -f Make_ming.mak clean' to clean up. +# +# NOTE: Sometimes 'GNU Make' will stop after building vimrun.exe -- I think +# it's just run out of memory or something. Run again, and it will continue +# with 'xxd'. +# +# "make upx" makes *compressed* versions of the 32 bit GUI and console EXEs, +# using the excellent UPX compressor: +# https://upx.github.io/ +# "make mpress" uses the MPRESS compressor for 32- and 64-bit EXEs: +# http://www.matcode.com/mpress.htm +# +# Maintained by Ron Aaron et al. +# Updated 2014 Oct 13. + +#>>>>> choose options: +# FEATURES=[TINY | NORMAL | HUGE] +# Set to TINY to make a minimal version (no optional features). +FEATURES=HUGE + +# Set to yes for a debug build. +DEBUG=no + +# Set to yes to create a mapfile. +#MAP=yes + +# Set to yes to measure code coverage. +COVERAGE=no + +# Better encryption support using libsodium. +# Set to yes or specify the path to the libsodium directory to enable it. +#SODIUM=yes + +# Set to SIZE for size, SPEED for speed, MAXSPEED for maximum optimization. +OPTIMIZE=MAXSPEED + +# Set to yes to make gvim, no for vim. +GUI=yes + +# Set to yes to enable the DLL support (EXPERIMENTAL). +# Creates vim{32,64}.dll, and stub gvim.exe and vim.exe. +# "GUI" should be also set to "yes". +#VIMDLL=yes + +# Set to no if you do not want to use DirectWrite (DirectX). +# MinGW-w64 is needed, and ARCH should be set to i686 or x86-64. +DIRECTX=yes + +# Disable Color emoji support +# (default is yes if DIRECTX=yes, requires WinSDK 8.1 or later.) +#COLOR_EMOJI=no + +# Set to one of i386, i486, i586, i686 as the minimum target processor. +# For amd64/x64 architecture set ARCH=x86-64 . +# If not set, it will be automatically detected. (Normally i686 or x86-64.) +#ARCH=i686 +# Set to yes to cross-compile from unix; no=native Windows (and Cygwin). +CROSS=no + +# Set to path to iconv.h and libiconv.a to enable using 'iconv.dll'. +# Use "yes" when the path does not need to be define. +#ICONV="." +ICONV=yes +GETTEXT=yes + +# Set to yes to include IME support. +IME=yes +DYNAMIC_IME=yes + +# Set to yes to enable writing a postscript file with :hardcopy. +POSTSCRIPT=no + +# Set to yes to enable OLE support. +OLE=no + +# Set the default $(WINVER). Use 0x0601 to make it work with Windows 7. +ifndef WINVER +WINVER = 0x0601 +endif + +# Set to yes to enable Cscope support. +CSCOPE=yes + +# Set to yes to enable Netbeans support (requires CHANNEL). +NETBEANS=$(GUI) + +# Set to yes to enable inter process communication. +ifeq (HUGE, $(FEATURES)) +CHANNEL=yes +else +CHANNEL=$(GUI) +endif + +# Set to yes to enable terminal support. +ifeq (HUGE, $(FEATURES)) +TERMINAL=yes +else +TERMINAL=no +endif + +# Set to yes to enable sound support. +ifneq ($(findstring $(FEATURES),HUGE),) +SOUND=yes +else +SOUND=no +endif + +ifndef CTAGS +# this assumes ctags is Exuberant ctags +CTAGS = ctags -I INIT+,INIT2+,INIT3+,INIT4+,INIT5+ --fields=+S +endif + +# Link against the shared version of libstdc++ by default. Set +# STATIC_STDCPLUS to "yes" to link against static version instead. +ifndef STATIC_STDCPLUS +STATIC_STDCPLUS=no +endif + + +# Link against the shared version of libwinpthread by default. Set +# STATIC_WINPTHREAD to "yes" to link against static version instead. +ifndef STATIC_WINPTHREAD +STATIC_WINPTHREAD=$(STATIC_STDCPLUS) +endif +# If you use TDM-GCC(-64), change HAS_GCC_EH to "no". +# This is used when STATIC_STDCPLUS=yes. +HAS_GCC_EH=yes + +# If the user doesn't want gettext, undefine it. +ifeq (no, $(GETTEXT)) +GETTEXT= +endif +# Added by E.F. Amatria 2001 Feb 23 +# Uncomment the first line and one of the following three if you want Native Language +# Support. You'll need gnu_gettext.win32, a MINGW32 Windows PORT of gettext by +# Franco Bez . It may be found at +# http://home.a-city.de/franco.bez/gettext/gettext_win32_en.html +# Tested with mingw32 with GCC-2.95.2 on Win98 +# Updated 2001 Jun 9 +#GETTEXT=c:/gettext.win32.msvcrt +#STATIC_GETTEXT=USE_STATIC_GETTEXT +#DYNAMIC_GETTEXT=USE_GETTEXT_DLL +#DYNAMIC_GETTEXT=USE_SAFE_GETTEXT_DLL +SAFE_GETTEXT_DLL_OBJ = $(GETTEXT)/src/safe_gettext_dll/safe_gettext_dll.o +# Alternatively, if you uncomment the two following lines, you get a "safe" version +# without linking the safe_gettext_dll.o object file. +#DYNAMIC_GETTEXT=DYNAMIC_GETTEXT +#GETTEXT_DYNAMIC=gnu_gettext.dll +INTLPATH=$(GETTEXT)/lib/mingw32 +INTLLIB=gnu_gettext + +# If you are using gettext-0.10.35 from http://sourceforge.net/projects/gettext +# or gettext-0.10.37 from http://sourceforge.net/projects/mingwrep/ +# uncomment the following, but I can't build a static version with them, ?-(| +#GETTEXT=c:/gettext-0.10.37-20010430 +#STATIC_GETTEXT=USE_STATIC_GETTEXT +#DYNAMIC_GETTEXT=DYNAMIC_GETTEXT +#INTLPATH=$(GETTEXT)/lib +#INTLLIB=intl + + +# Command definitions (depends on cross-compiling and shell) +ifeq ($(CROSS),yes) +# cross-compiler prefix: + ifndef CROSS_COMPILE +CROSS_COMPILE = i586-pc-mingw32msvc- + endif +DEL = rm +MKDIR = mkdir -p +DIRSLASH = / +else +# normal (Windows) compilation: + ifndef CROSS_COMPILE +CROSS_COMPILE = + endif + +# About the "sh.exe" condition, as explained by Ken Takata: +# +# If the makefile is executed with mingw32-make and sh.exe is not found in +# $PATH, then $SHELL is set to "sh.exe" (without any path). In this case, +# unix-like commands might not work and a dos-style path is needed. +# +# If the makefile is executed with mingw32-make and sh.exe IS found in $PATH, +# then $SHELL is set with the actual path of sh.exe (e.g. +# "C:/msys64/usr/bin/sh.exe"). In this case, unix-like commands can be used. +# +# If it is executed by the "make" command from cmd.exe, $SHELL is set to +# "/bin/sh". If the "make" command is in the $PATH, other unix-like commands +# might also work. +# +# If it is executed by the "make" command from a unix-like shell, +# $SHELL is set with the unix-style path (e.g. "/bin/bash"). +# In this case, unix-like commands can be used. +# + ifneq (sh.exe, $(SHELL)) +DEL = rm +MKDIR = mkdir -p +DIRSLASH = / + else +DEL = del +MKDIR = mkdir +DIRSLASH = \\ + endif +endif +# set $CC to "gcc" unless it matches "clang" +ifeq ($(findstring clang,$(CC)),) +CC := $(CROSS_COMPILE)gcc +endif +# set $CXX to "g++" unless it matches "clang" +ifeq ($(findstring clang,$(CXX)),) +CXX := $(CROSS_COMPILE)g++ +endif +ifeq ($(UNDER_CYGWIN),yes) +WINDRES := $(CROSS_COMPILE)windres +else ifeq ($(findstring clang,$(CC)),) +WINDRES := windres +else +WINDRES := llvm-windres +endif + +# Get the default ARCH. +ifndef ARCH +ARCH := $(shell $(CC) -dumpmachine | sed -e 's/-.*//' -e 's/_/-/' -e 's/^mingw32$$/i686/') +endif + + +# Perl interface: +# PERL=[Path to Perl directory] (Set inside Make_cyg.mak or Make_ming.mak) +# DYNAMIC_PERL=yes (to load the Perl DLL dynamically) +# PERL_VER=[Perl version, eg 56, 58, 510] (default is 524) +ifdef PERL + ifndef PERL_VER +PERL_VER=524 + endif + ifndef DYNAMIC_PERL +DYNAMIC_PERL=yes + endif +# on Linux, for cross-compile, it's here: +#PERLLIB=/home/ron/ActivePerl/lib +# on NT, it's here: +PERLEXE=$(PERL)/bin/perl +PERLLIB=$(PERL)/lib +PERLLIBS=$(PERLLIB)/Core + ifeq ($(UNDER_CYGWIN),yes) +PERLTYPEMAP:=$(shell cygpath -m $(PERLLIB)/ExtUtils/typemap) +XSUBPPTRY:=$(shell cygpath -m $(PERLLIB)/ExtUtils/xsubpp) + else +PERLTYPEMAP=$(PERLLIB)/ExtUtils/typemap +XSUBPPTRY=$(PERLLIB)/ExtUtils/xsubpp + endif +XSUBPP_EXISTS=$(shell $(PERLEXE) -e "print 1 unless -e '$(XSUBPPTRY)'") + ifeq "$(XSUBPP_EXISTS)" "" +XSUBPP=$(PERLEXE) $(XSUBPPTRY) + else +XSUBPP=xsubpp + endif +endif + +# Lua interface: +# LUA=[Path to Lua directory] (Set inside Make_cyg.mak or Make_ming.mak) +# LUA_LIBDIR=[Path to Lua library directory] (default: $LUA/lib) +# LUA_INCDIR=[Path to Lua include directory] (default: $LUA/include) +# DYNAMIC_LUA=yes (to load the Lua DLL dynamically) +# LUA_VER=[Lua version, eg 51, 52] (default is 53) +ifdef LUA + ifndef DYNAMIC_LUA +DYNAMIC_LUA=yes + endif + + ifndef LUA_VER +LUA_VER=53 + endif + + ifeq (no,$(DYNAMIC_LUA)) +LUA_LIBDIR = $(LUA)/lib +LUA_LIB = -L$(LUA_LIBDIR) -llua + endif + +endif + +# MzScheme interface: +# MZSCHEME=[Path to MzScheme directory] (Set inside Make_cyg.mak or Make_ming.mak) +# DYNAMIC_MZSCHEME=yes (to load the MzScheme DLL dynamically) +# MZSCHEME_VER=[MzScheme version] (default is 3m_a0solc (6.6)) +# Used for the DLL file name. E.g.: +# C:\Program Files (x86)\Racket\lib\libracket3m_XXXXXX.dll +# MZSCHEME_DEBUG=no +ifdef MZSCHEME + ifndef DYNAMIC_MZSCHEME +DYNAMIC_MZSCHEME=yes + endif + + ifndef MZSCHEME_VER +MZSCHEME_VER=3m_a0solc + endif + +# for version 4.x we need to generate byte-code for Scheme base + ifndef MZSCHEME_GENERATE_BASE +MZSCHEME_GENERATE_BASE=no + endif + + ifneq ($(wildcard $(MZSCHEME)/lib/msvc/libmzsch$(MZSCHEME_VER).lib),) +MZSCHEME_MAIN_LIB=mzsch + else +MZSCHEME_MAIN_LIB=racket + endif + + ifndef MZSCHEME_PRECISE_GC +MZSCHEME_PRECISE_GC=no + ifneq ($(wildcard $(MZSCHEME)\lib\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll),) + ifeq ($(wildcard $(MZSCHEME)\lib\libmzgc$(MZSCHEME_VER).dll),) +MZSCHEME_PRECISE_GC=yes + endif + else + ifneq ($(wildcard $(MZSCHEME)\lib\msvc\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib),) + ifeq ($(wildcard $(MZSCHEME)\lib\msvc\libmzgc$(MZSCHEME_VER).lib),) +MZSCHEME_PRECISE_GC=yes + endif + endif + endif + endif + + ifeq (no,$(DYNAMIC_MZSCHEME)) + ifeq (yes,$(MZSCHEME_PRECISE_GC)) +MZSCHEME_LIB=-l$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER) + else +MZSCHEME_LIB=-l$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER) -lmzgc$(MZSCHEME_VER) + endif +# the modern MinGW can dynamically link to dlls directly. +# point MZSCHEME_DLLS to where you put libmzschXXXXXXX.dll and libgcXXXXXXX.dll + ifndef MZSCHEME_DLLS +MZSCHEME_DLLS=$(MZSCHEME) + endif +MZSCHEME_LIBDIR=-L$(MZSCHEME_DLLS) -L$(MZSCHEME_DLLS)\lib + endif + +endif + +# Python interface: +# PYTHON=[Path to Python directory] (Set inside Make_cyg.mak or Make_ming.mak) +# DYNAMIC_PYTHON=yes (to load the Python DLL dynamically) +# PYTHON_VER=[Python version, eg 22, 23, ..., 27] (default is 27) +ifdef PYTHON + ifndef DYNAMIC_PYTHON +DYNAMIC_PYTHON=yes + endif + + ifndef PYTHON_VER +PYTHON_VER=27 + endif + ifndef DYNAMIC_PYTHON_DLL +DYNAMIC_PYTHON_DLL=python$(PYTHON_VER).dll + endif + ifdef PYTHON_HOME +PYTHON_HOME_DEF=-DPYTHON_HOME=\"$(PYTHON_HOME)\" + endif + + ifeq (no,$(DYNAMIC_PYTHON)) +PYTHONLIB=-L$(PYTHON)/libs -lpython$(PYTHON_VER) + endif +# my include files are in 'win32inc' on Linux, and 'include' in the standard +# NT distro (ActiveState) + ifndef PYTHONINC + ifeq ($(CROSS),no) +PYTHONINC=-I $(PYTHON)/include + else +PYTHONINC=-I $(PYTHON)/win32inc + endif + endif +endif + +# Python3 interface: +# PYTHON3=[Path to Python3 directory] (Set inside Make_cyg.mak or Make_ming.mak) +# DYNAMIC_PYTHON3=yes (to load the Python3 DLL dynamically) +# PYTHON3_VER=[Python3 version, eg 31, 32] (default is 36) +ifdef PYTHON3 + ifndef DYNAMIC_PYTHON3 +DYNAMIC_PYTHON3=yes + endif + + ifndef PYTHON3_VER +PYTHON3_VER=36 + endif + ifndef DYNAMIC_PYTHON3_DLL +DYNAMIC_PYTHON3_DLL=python$(PYTHON3_VER).dll + endif + ifdef PYTHON3_HOME +PYTHON3_HOME_DEF=-DPYTHON3_HOME=L\"$(PYTHON3_HOME)\" + endif + + ifeq (no,$(DYNAMIC_PYTHON3)) +PYTHON3LIB=-L$(PYTHON3)/libs -lpython$(PYTHON3_VER) + endif + + ifndef PYTHON3INC + ifeq ($(CROSS),no) +PYTHON3INC=-I $(PYTHON3)/include + else +PYTHON3INC=-I $(PYTHON3)/win32inc + endif + endif +endif + +# TCL interface: +# TCL=[Path to TCL directory] (Set inside Make_cyg.mak or Make_ming.mak) +# DYNAMIC_TCL=yes (to load the TCL DLL dynamically) +# TCL_VER=[TCL version, eg 83, 84] (default is 86) +# TCL_VER_LONG=[Tcl version, eg 8.3] (default is 8.6) +# You must set TCL_VER_LONG when you set TCL_VER. +# TCL_DLL=[TCL dll name, eg tcl86.dll] (default is tcl86.dll) +ifdef TCL + ifndef DYNAMIC_TCL +DYNAMIC_TCL=yes + endif + ifndef TCL_VER +TCL_VER = 86 + endif + ifndef TCL_VER_LONG +TCL_VER_LONG = 8.6 + endif + ifndef TCL_DLL +TCL_DLL = tcl$(TCL_VER).dll + endif +TCLINC += -I$(TCL)/include +endif + + +# Ruby interface: +# RUBY=[Path to Ruby directory] (Set inside Make_cyg.mak or Make_ming.mak) +# DYNAMIC_RUBY=yes (to load the Ruby DLL dynamically, "no" for static) +# RUBY_VER=[Ruby version, eg 19, 22] (default is 22) +# RUBY_API_VER_LONG=[Ruby API version, eg 1.9.1, 2.2.0] +# (default is 2.2.0) +# You must set RUBY_API_VER_LONG when changing RUBY_VER. +# Note: If you use Ruby 1.9.3, set as follows: +# RUBY_VER=19 +# RUBY_API_VER_LONG=1.9.1 (not 1.9.3, because the API version is 1.9.1.) +ifdef RUBY + ifndef DYNAMIC_RUBY +DYNAMIC_RUBY=yes + endif +# Set default value + ifndef RUBY_VER +RUBY_VER = 22 + endif + ifndef RUBY_VER_LONG +RUBY_VER_LONG = 2.2.0 + endif + ifndef RUBY_API_VER_LONG +RUBY_API_VER_LONG = $(RUBY_VER_LONG) + endif + ifndef RUBY_API_VER +RUBY_API_VER = $(subst .,,$(RUBY_API_VER_LONG)) + endif + + ifndef RUBY_PLATFORM + ifneq ($(wildcard $(RUBY)/lib/ruby/$(RUBY_API_VER_LONG)/i386-mingw32),) +RUBY_PLATFORM = i386-mingw32 + else ifneq ($(wildcard $(RUBY)/lib/ruby/$(RUBY_API_VER_LONG)/x64-mingw32),) +RUBY_PLATFORM = x64-mingw32 + else ifneq ($(wildcard $(RUBY)/lib/ruby/$(RUBY_API_VER_LONG)/x64-mingw-ucrt),) +RUBY_PLATFORM = x64-mingw-ucrt + else +RUBY_PLATFORM = i386-mswin32 + endif + endif + + ifndef RUBY_INSTALL_NAME + ifndef RUBY_MSVCRT_NAME +# Base name of msvcrXX.dll which is used by ruby's dll. +RUBY_MSVCRT_NAME = msvcrt + endif + ifeq ($(RUBY_PLATFORM),x64-mingw-ucrt) +RUBY_INSTALL_NAME = x64-ucrt-ruby$(RUBY_API_VER) + else ifeq ($(ARCH),x86-64) +RUBY_INSTALL_NAME = x64-$(RUBY_MSVCRT_NAME)-ruby$(RUBY_API_VER) + else +RUBY_INSTALL_NAME = $(RUBY_MSVCRT_NAME)-ruby$(RUBY_API_VER) + endif + endif + +RUBYINC = -I $(RUBY)/include/ruby-$(RUBY_API_VER_LONG) -I $(RUBY)/include/ruby-$(RUBY_API_VER_LONG)/$(RUBY_PLATFORM) + ifeq (no, $(DYNAMIC_RUBY)) +RUBYLIB = -L$(RUBY)/lib -l$(RUBY_INSTALL_NAME) + endif + +endif # RUBY + +# See feature.h for a list of options. +# Any other defines can be included here. +DEF_GUI=-DFEAT_GUI_MSWIN -DFEAT_CLIPBOARD +DEFINES=-DWIN32 -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER) \ + -DHAVE_PATHDEF -DFEAT_$(FEATURES) -DHAVE_STDINT_H +ifeq ($(ARCH),x86-64) +DEFINES+=-DMS_WIN64 +endif + +#>>>>> end of choices +########################################################################### + +CFLAGS = -I. -Iproto $(DEFINES) -pipe -march=$(ARCH) -Wall +# To get additional compiler warnings +#CFLAGS += -Wextra -pedantic +CXXFLAGS = -std=gnu++11 +# This used to have --preprocessor, but it's no longer supported +WINDRES_FLAGS = +EXTRA_LIBS = + +ifdef GETTEXT +DEFINES += -DHAVE_GETTEXT -DHAVE_LOCALE_H +GETTEXTINCLUDE = $(GETTEXT)/include +GETTEXTLIB = $(INTLPATH) + ifeq (yes, $(GETTEXT)) +DEFINES += -DDYNAMIC_GETTEXT + else ifdef DYNAMIC_GETTEXT +DEFINES += -D$(DYNAMIC_GETTEXT) + ifdef GETTEXT_DYNAMIC +DEFINES += -DGETTEXT_DYNAMIC -DGETTEXT_DLL=\"$(GETTEXT_DYNAMIC)\" + endif + endif +endif + +ifdef PERL +CFLAGS += -I$(PERLLIBS) -DFEAT_PERL -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS + ifeq (yes, $(DYNAMIC_PERL)) +CFLAGS += -DDYNAMIC_PERL -DDYNAMIC_PERL_DLL=\"perl$(PERL_VER).dll\" +EXTRA_LIBS += -L$(PERLLIBS) -lperl$(PERL_VER) + endif +endif + +ifdef LUA +LUA_INCDIR = $(LUA)/include +CFLAGS += -I$(LUA_INCDIR) -I$(LUA) -DFEAT_LUA + ifeq (yes, $(DYNAMIC_LUA)) +CFLAGS += -DDYNAMIC_LUA -DDYNAMIC_LUA_DLL=\"lua$(LUA_VER).dll\" + endif +endif + +ifdef MZSCHEME + ifndef MZSCHEME_COLLECTS +MZSCHEME_COLLECTS=$(MZSCHEME)/collects + ifeq (yes, $(UNDER_CYGWIN)) +MZSCHEME_COLLECTS:=$(shell cygpath -m $(MZSCHEME_COLLECTS) | sed -e 's/ /\\ /g') + endif + endif +CFLAGS += -I$(MZSCHEME)/include -DFEAT_MZSCHEME -DMZSCHEME_COLLECTS=\"$(MZSCHEME_COLLECTS)\" + ifeq (yes, $(DYNAMIC_MZSCHEME)) + ifeq (yes, $(MZSCHEME_PRECISE_GC)) +# Precise GC does not use separate dll +CFLAGS += -DDYNAMIC_MZSCHEME -DDYNAMIC_MZSCH_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\" -DDYNAMIC_MZGC_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\" + else +CFLAGS += -DDYNAMIC_MZSCHEME -DDYNAMIC_MZSCH_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\" -DDYNAMIC_MZGC_DLL=\"libmzgc$(MZSCHEME_VER).dll\" + endif + endif + ifeq (yes, "$(MZSCHEME_DEBUG)") +CFLAGS += -DMZSCHEME_FORCE_GC + endif +endif + +ifdef RUBY +CFLAGS += -DFEAT_RUBY $(RUBYINC) + ifeq (yes, $(DYNAMIC_RUBY)) +CFLAGS += -DDYNAMIC_RUBY -DDYNAMIC_RUBY_DLL=\"$(RUBY_INSTALL_NAME).dll\" + endif +CFLAGS += -DRUBY_VERSION=$(RUBY_VER) + ifneq ($(findstring w64-mingw32,$(CC)),) +# A workaround for MinGW-w64 +CFLAGS += -DHAVE_STRUCT_TIMESPEC -DHAVE_STRUCT_TIMEZONE + endif +endif + +ifdef PYTHON +CFLAGS += -DFEAT_PYTHON + ifeq (yes, $(DYNAMIC_PYTHON)) +CFLAGS += -DDYNAMIC_PYTHON -DDYNAMIC_PYTHON_DLL=\"$(DYNAMIC_PYTHON_DLL)\" + endif +endif + +ifdef PYTHON3 +CFLAGS += -DFEAT_PYTHON3 + ifeq (yes, $(DYNAMIC_PYTHON3)) +CFLAGS += -DDYNAMIC_PYTHON3 -DDYNAMIC_PYTHON3_DLL=\"$(DYNAMIC_PYTHON3_DLL)\" + else +CFLAGS += -DPYTHON3_DLL=\"$(DYNAMIC_PYTHON3_DLL)\" + endif +endif + +ifdef TCL +CFLAGS += -DFEAT_TCL $(TCLINC) + ifeq (yes, $(DYNAMIC_TCL)) +CFLAGS += -DDYNAMIC_TCL -DDYNAMIC_TCL_DLL=\"$(TCL_DLL)\" -DDYNAMIC_TCL_VER=\"$(TCL_VER_LONG)\" + endif +endif + +ifeq ($(POSTSCRIPT),yes) +DEFINES += -DMSWINPS +endif + +ifeq (yes, $(OLE)) +DEFINES += -DFEAT_OLE +endif + +ifeq ($(CSCOPE),yes) +DEFINES += -DFEAT_CSCOPE +endif + +ifeq ($(NETBEANS),yes) +# Only allow NETBEANS for a GUI build. + ifeq (yes, $(GUI)) +DEFINES += -DFEAT_NETBEANS_INTG + + ifeq ($(NBDEBUG), yes) +DEFINES += -DNBDEBUG +NBDEBUG_INCL = nbdebug.h +NBDEBUG_SRC = nbdebug.c + endif + endif +endif + +ifeq ($(CHANNEL),yes) +DEFINES += -DFEAT_JOB_CHANNEL -DFEAT_IPV6 + ifeq ($(shell expr "$$(($(WINVER)))" \>= "$$((0x600))"),1) +DEFINES += -DHAVE_INET_NTOP + endif +endif + +ifeq ($(TERMINAL),yes) +DEFINES += -DFEAT_TERMINAL +TERM_DEPS = \ + libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h \ + libvterm/src/rect.h \ + libvterm/src/utf8.h \ + libvterm/src/vterm_internal.h +endif + +ifeq ($(SOUND),yes) +DEFINES += -DFEAT_SOUND +endif + +# DirectWrite (DirectX) +ifeq ($(DIRECTX),yes) +# Only allow DirectWrite for a GUI build. + ifeq (yes, $(GUI)) +DEFINES += -DFEAT_DIRECTX -DDYNAMIC_DIRECTX + ifneq ($(COLOR_EMOJI),no) +DEFINES += -DFEAT_DIRECTX_COLOR_EMOJI + endif + endif +endif + +ifdef SODIUM +DEFINES += -DHAVE_SODIUM + ifeq ($(SODIUM),yes) +SODIUM_DLL = libsodium-23.dll + else +SODIUM_DLL = libsodium.dll +CFLAGS += -I $(SODIUM)/include + endif + ifndef DYNAMIC_SODIUM +DYNAMIC_SODIUM=yes + endif + ifeq ($(DYNAMIC_SODIUM),yes) +DEFINES += -DDYNAMIC_SODIUM -DDYNAMIC_SODIUM_DLL=\"$(SODIUM_DLL)\" + else +SODIUMLIB = -lsodium + endif +endif + +# Only allow XPM for a GUI build. +ifeq (yes, $(GUI)) + + ifndef XPM + ifeq ($(ARCH),i386) +XPM = xpm/x86 + endif + ifeq ($(ARCH),i486) +XPM = xpm/x86 + endif + ifeq ($(ARCH),i586) +XPM = xpm/x86 + endif + ifeq ($(ARCH),i686) +XPM = xpm/x86 + endif + ifeq ($(ARCH),x86-64) +XPM = xpm/x64 + endif + endif + ifdef XPM + ifneq ($(XPM),no) +CFLAGS += -DFEAT_XPM_W32 -I $(XPM)/include -I $(XPM)/../include + endif + endif + +endif + +ifeq ($(DEBUG),yes) +CFLAGS += -g -fstack-check +DEBUG_SUFFIX=d +else + ifeq ($(OPTIMIZE), SIZE) +CFLAGS += -Os + else ifeq ($(OPTIMIZE), MAXSPEED) +CFLAGS += -O3 +CFLAGS += -fomit-frame-pointer + ifeq ($(findstring clang,$(CC)),) +# Only GCC supports the "reg-struct-return" option. Clang doesn't support this. +CFLAGS += -freg-struct-return + endif + else # SPEED +CFLAGS += -O2 + endif +LFLAGS += -s +endif + +ifeq ($(COVERAGE),yes) +CFLAGS += --coverage +LFLAGS += --coverage +endif + +# If the ASAN=yes argument is supplied, then compile Vim with the address +# sanitizer (asan). Only supported by MingW64 clang compiler. +# May make Vim twice as slow. Errors are reported on stderr. +# More at: https://code.google.com/p/address-sanitizer/ +# Useful environment variable: +# set ASAN_OPTIONS=print_stacktrace=1 log_path=asan +ifeq ($(ASAN),yes) +#CFLAGS += -g -O0 -fsanitize-recover=all -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer +CFLAGS += -g -O0 -fsanitize-recover=all -fsanitize=address -fno-omit-frame-pointer +endif + +LIB = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lcomdlg32 -lcomctl32 -lnetapi32 -lversion +GUIOBJ = $(OUTDIR)/gui.o $(OUTDIR)/gui_w32.o $(OUTDIR)/gui_beval.o +CUIOBJ = $(OUTDIR)/iscygpty.o +OBJ = \ + $(OUTDIR)/alloc.o \ + $(OUTDIR)/arabic.o \ + $(OUTDIR)/arglist.o \ + $(OUTDIR)/autocmd.o \ + $(OUTDIR)/beval.o \ + $(OUTDIR)/blob.o \ + $(OUTDIR)/blowfish.o \ + $(OUTDIR)/buffer.o \ + $(OUTDIR)/bufwrite.o \ + $(OUTDIR)/change.o \ + $(OUTDIR)/charset.o \ + $(OUTDIR)/cindent.o \ + $(OUTDIR)/clientserver.o \ + $(OUTDIR)/clipboard.o \ + $(OUTDIR)/cmdexpand.o \ + $(OUTDIR)/cmdhist.o \ + $(OUTDIR)/crypt.o \ + $(OUTDIR)/crypt_zip.o \ + $(OUTDIR)/debugger.o \ + $(OUTDIR)/dict.o \ + $(OUTDIR)/diff.o \ + $(OUTDIR)/digraph.o \ + $(OUTDIR)/drawline.o \ + $(OUTDIR)/drawscreen.o \ + $(OUTDIR)/edit.o \ + $(OUTDIR)/eval.o \ + $(OUTDIR)/evalbuffer.o \ + $(OUTDIR)/evalfunc.o \ + $(OUTDIR)/evalvars.o \ + $(OUTDIR)/evalwindow.o \ + $(OUTDIR)/ex_cmds.o \ + $(OUTDIR)/ex_cmds2.o \ + $(OUTDIR)/ex_docmd.o \ + $(OUTDIR)/ex_eval.o \ + $(OUTDIR)/ex_getln.o \ + $(OUTDIR)/fileio.o \ + $(OUTDIR)/filepath.o \ + $(OUTDIR)/findfile.o \ + $(OUTDIR)/float.o \ + $(OUTDIR)/fold.o \ + $(OUTDIR)/getchar.o \ + $(OUTDIR)/gui_xim.o \ + $(OUTDIR)/hardcopy.o \ + $(OUTDIR)/hashtab.o \ + $(OUTDIR)/help.o \ + $(OUTDIR)/highlight.o \ + $(OUTDIR)/if_cscope.o \ + $(OUTDIR)/indent.o \ + $(OUTDIR)/insexpand.o \ + $(OUTDIR)/json.o \ + $(OUTDIR)/list.o \ + $(OUTDIR)/locale.o \ + $(OUTDIR)/logfile.o \ + $(OUTDIR)/main.o \ + $(OUTDIR)/map.o \ + $(OUTDIR)/mark.o \ + $(OUTDIR)/match.o \ + $(OUTDIR)/memfile.o \ + $(OUTDIR)/memline.o \ + $(OUTDIR)/menu.o \ + $(OUTDIR)/message.o \ + $(OUTDIR)/misc1.o \ + $(OUTDIR)/misc2.o \ + $(OUTDIR)/mouse.o \ + $(OUTDIR)/move.o \ + $(OUTDIR)/mbyte.o \ + $(OUTDIR)/normal.o \ + $(OUTDIR)/ops.o \ + $(OUTDIR)/option.o \ + $(OUTDIR)/optionstr.o \ + $(OUTDIR)/os_mswin.o \ + $(OUTDIR)/os_win32.o \ + $(OUTDIR)/pathdef.o \ + $(OUTDIR)/popupmenu.o \ + $(OUTDIR)/popupwin.o \ + $(OUTDIR)/profiler.o \ + $(OUTDIR)/quickfix.o \ + $(OUTDIR)/regexp.o \ + $(OUTDIR)/register.o \ + $(OUTDIR)/scriptfile.o \ + $(OUTDIR)/screen.o \ + $(OUTDIR)/search.o \ + $(OUTDIR)/session.o \ + $(OUTDIR)/sha256.o \ + $(OUTDIR)/sign.o \ + $(OUTDIR)/spell.o \ + $(OUTDIR)/spellfile.o \ + $(OUTDIR)/spellsuggest.o \ + $(OUTDIR)/strings.o \ + $(OUTDIR)/syntax.o \ + $(OUTDIR)/tag.o \ + $(OUTDIR)/term.o \ + $(OUTDIR)/testing.o \ + $(OUTDIR)/textformat.o \ + $(OUTDIR)/textobject.o \ + $(OUTDIR)/textprop.o \ + $(OUTDIR)/time.o \ + $(OUTDIR)/typval.o \ + $(OUTDIR)/ui.o \ + $(OUTDIR)/undo.o \ + $(OUTDIR)/usercmd.o \ + $(OUTDIR)/userfunc.o \ + $(OUTDIR)/version.o \ + $(OUTDIR)/vim9class.o \ + $(OUTDIR)/vim9cmds.o \ + $(OUTDIR)/vim9compile.o \ + $(OUTDIR)/vim9execute.o \ + $(OUTDIR)/vim9expr.o \ + $(OUTDIR)/vim9instr.o \ + $(OUTDIR)/vim9script.o \ + $(OUTDIR)/vim9type.o \ + $(OUTDIR)/viminfo.o \ + $(OUTDIR)/winclip.o \ + $(OUTDIR)/window.o + +ifeq ($(VIMDLL),yes) +OBJ += $(OUTDIR)/os_w32dll.o $(OUTDIR)/vimresd.o +EXEOBJC = $(OUTDIR)/os_w32exec.o $(OUTDIR)/vimresc.o +EXEOBJG = $(OUTDIR)/os_w32exeg.o $(OUTDIR)/vimresg.o +else +OBJ += $(OUTDIR)/os_w32exe.o $(OUTDIR)/vimres.o +endif + +ifdef PERL +OBJ += $(OUTDIR)/if_perl.o +endif +ifdef LUA +OBJ += $(OUTDIR)/if_lua.o +endif +ifdef MZSCHEME +OBJ += $(OUTDIR)/if_mzsch.o +MZSCHEME_INCL = if_mzsch.h + ifeq (yes,$(MZSCHEME_GENERATE_BASE)) +CFLAGS += -DINCLUDE_MZSCHEME_BASE +MZ_EXTRA_DEP += mzscheme_base.c + endif + ifeq (yes,$(MZSCHEME_PRECISE_GC)) +CFLAGS += -DMZ_PRECISE_GC + endif +endif +ifdef PYTHON +OBJ += $(OUTDIR)/if_python.o +endif +ifdef PYTHON3 +OBJ += $(OUTDIR)/if_python3.o +endif +ifdef RUBY +OBJ += $(OUTDIR)/if_ruby.o +endif +ifdef TCL +OBJ += $(OUTDIR)/if_tcl.o +endif + +ifeq ($(NETBEANS),yes) + ifneq ($(CHANNEL),yes) +# Cannot use Netbeans without CHANNEL +NETBEANS=no + else ifneq (yes, $(GUI)) +# Cannot use Netbeans without GUI. +NETBEANS=no + else +OBJ += $(OUTDIR)/netbeans.o + endif +endif + +ifeq ($(CHANNEL),yes) +OBJ += $(OUTDIR)/job.o $(OUTDIR)/channel.o +LIB += -lwsock32 -lws2_32 +endif + +ifeq ($(DIRECTX),yes) +# Only allow DIRECTX for a GUI build. + ifeq (yes, $(GUI)) +OBJ += $(OUTDIR)/gui_dwrite.o +LIB += -ld2d1 -ldwrite +USE_STDCPLUS = yes + endif +endif +ifneq ($(XPM),no) +# Only allow XPM for a GUI build. + ifeq (yes, $(GUI)) +OBJ += $(OUTDIR)/xpm_w32.o +# You'll need libXpm.a from http://gnuwin32.sf.net +LIB += -L$(XPM)/lib -lXpm + endif +endif + +ifeq ($(TERMINAL),yes) +OBJ += $(OUTDIR)/terminal.o \ + $(OUTDIR)/vterm_encoding.o \ + $(OUTDIR)/vterm_keyboard.o \ + $(OUTDIR)/vterm_mouse.o \ + $(OUTDIR)/vterm_parser.o \ + $(OUTDIR)/vterm_pen.o \ + $(OUTDIR)/vterm_screen.o \ + $(OUTDIR)/vterm_state.o \ + $(OUTDIR)/vterm_unicode.o \ + $(OUTDIR)/vterm_vterm.o +endif + +ifeq ($(SOUND),yes) +OBJ += $(OUTDIR)/sound.o +endif + +# Include xdiff +OBJ += $(OUTDIR)/xdiffi.o \ + $(OUTDIR)/xemit.o \ + $(OUTDIR)/xprepare.o \ + $(OUTDIR)/xutils.o \ + $(OUTDIR)/xhistogram.o \ + $(OUTDIR)/xpatience.o + +XDIFF_DEPS = \ + xdiff/xdiff.h \ + xdiff/xdiffi.h \ + xdiff/xemit.h \ + xdiff/xinclude.h \ + xdiff/xmacros.h \ + xdiff/xprepare.h \ + xdiff/xtypes.h \ + xdiff/xutils.h + +ifdef MZSCHEME +MZSCHEME_SUFFIX = Z +endif + +LFLAGS += -municode + +ifeq ($(VIMDLL),yes) +VIMEXE := vim$(DEBUG_SUFFIX).exe +GVIMEXE := gvim$(DEBUG_SUFFIX).exe + ifeq ($(ARCH),x86-64) +VIMDLLBASE := vim64$(DEBUG_SUFFIX) + else +VIMDLLBASE := vim32$(DEBUG_SUFFIX) + endif +TARGET = $(VIMDLLBASE).dll +LFLAGS += -shared +EXELFLAGS += -municode + ifneq ($(DEBUG),yes) +EXELFLAGS += -s + endif + ifeq ($(COVERAGE),yes) +EXELFLAGS += --coverage + endif +DEFINES += $(DEF_GUI) -DVIMDLL +OBJ += $(GUIOBJ) $(CUIOBJ) +OUTDIR = dobj$(DEBUG_SUFFIX)$(MZSCHEME_SUFFIX)$(ARCH) +MAIN_TARGET = $(GVIMEXE) $(VIMEXE) $(VIMDLLBASE).dll +else ifeq ($(GUI),yes) +TARGET := gvim$(DEBUG_SUFFIX).exe +DEFINES += $(DEF_GUI) +OBJ += $(GUIOBJ) +LFLAGS += -mwindows +OUTDIR = gobj$(DEBUG_SUFFIX)$(MZSCHEME_SUFFIX)$(ARCH) +MAIN_TARGET = $(TARGET) +else +OBJ += $(CUIOBJ) +TARGET := vim$(DEBUG_SUFFIX).exe +OUTDIR = obj$(DEBUG_SUFFIX)$(MZSCHEME_SUFFIX)$(ARCH) +MAIN_TARGET = $(TARGET) +endif + +ifdef GETTEXT + ifneq (yes, $(GETTEXT)) +CFLAGS += -I$(GETTEXTINCLUDE) + ifndef STATIC_GETTEXT +LIB += -L$(GETTEXTLIB) -l$(INTLLIB) + ifeq (USE_SAFE_GETTEXT_DLL, $(DYNAMIC_GETTEXT)) +OBJ+=$(SAFE_GETTEXT_DLL_OBJ) + endif + else +LIB += -L$(GETTEXTLIB) -lintl + endif + endif +endif + +ifdef PERL + ifeq (no, $(DYNAMIC_PERL)) +LIB += -L$(PERLLIBS) -lperl$(PERL_VER) + endif +endif + +ifdef TCL +LIB += -L$(TCL)/lib + ifeq (yes, $(DYNAMIC_TCL)) +LIB += -ltclstub$(TCL_VER) + else +LIB += -ltcl$(TCL_VER) + endif +endif + +ifeq (yes, $(OLE)) +LIB += -loleaut32 +OBJ += $(OUTDIR)/if_ole.o +USE_STDCPLUS = yes +endif + +ifeq (yes, $(IME)) +DEFINES += -DFEAT_MBYTE_IME + ifeq (yes, $(DYNAMIC_IME)) +DEFINES += -DDYNAMIC_IME + else +LIB += -limm32 + endif +endif + +ifdef ICONV + ifneq (yes, $(ICONV)) +LIB += -L$(ICONV) +CFLAGS += -I$(ICONV) + endif +DEFINES+=-DDYNAMIC_ICONV +endif + +ifeq (yes, $(SOUND)) +LIB += -lwinmm +endif + +ifeq (yes, $(USE_STDCPLUS)) +LINK = $(CXX) + ifeq (yes, $(STATIC_STDCPLUS)) +#LIB += -static-libstdc++ -static-libgcc +LIB += -Wl,-Bstatic -lstdc++ -lgcc -Wl,-Bdynamic + endif +else +LINK = $(CC) +endif + +ifeq (yes, $(STATIC_WINPTHREAD)) + ifeq (yes, $(HAS_GCC_EH)) +LIB += -lgcc_eh + endif +LIB += -Wl,-Bstatic -lwinpthread -Wl,-Bdynamic +endif + +ifeq (yes, $(MAP)) +LFLAGS += -Wl,-Map=$(TARGET).map +endif + +# The default stack size on Windows is 2 MB. With the default stack size, the +# following tests fail with the clang address sanitizer: +# Test_listdict_compare, Test_listdict_compare_complex, Test_deep_recursion, +# Test_map_error, Test_recursive_define, Test_recursive_addstate +# To increase the stack size to 16MB, uncomment the following line: +#LFLAGS += -Wl,-stack -Wl,0x1000000 + +all: $(MAIN_TARGET) vimrun.exe xxd/xxd.exe tee/tee.exe install.exe uninstall.exe GvimExt/gvimext.dll + +vimrun.exe: vimrun.c + $(CC) $(CFLAGS) -o vimrun.exe vimrun.c $(LIB) + +install.exe: dosinst.c dosinst.h version.h + $(CC) $(CFLAGS) -o install.exe dosinst.c $(LIB) -lole32 -luuid + +uninstall.exe: uninstall.c dosinst.h version.h + $(CC) $(CFLAGS) -o uninstall.exe uninstall.c $(LIB) -lole32 + +$(OBJ): | $(OUTDIR) + +$(EXEOBJG): | $(OUTDIR) + +$(EXEOBJC): | $(OUTDIR) + +ifeq ($(VIMDLL),yes) +$(TARGET): $(OBJ) + $(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid -lgdi32 $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB) $(SODIUMLIB) + +$(GVIMEXE): $(EXEOBJG) $(VIMDLLBASE).dll + $(CC) -L. $(EXELFLAGS) -mwindows -o $@ $(EXEOBJG) -l$(VIMDLLBASE) + +$(VIMEXE): $(EXEOBJC) $(VIMDLLBASE).dll + $(CC) -L. $(EXELFLAGS) -o $@ $(EXEOBJC) -l$(VIMDLLBASE) +else +$(TARGET): $(OBJ) + $(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB) $(SODIUMLIB) +endif + +upx: exes + upx gvim.exe + upx vim.exe + +mpress: exes + mpress gvim.exe + mpress vim.exe + +xxd/xxd.exe: xxd/xxd.c + $(MAKE) -C xxd -f Make_ming.mak CC='$(CC)' + +tee/tee.exe: tee/tee.c + $(MAKE) -C tee -f Make_ming.mak CC='$(CC)' + +GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h + $(MAKE) -C GvimExt -f Make_ming.mak CROSS=$(CROSS) CROSS_COMPILE=$(CROSS_COMPILE) CXX='$(CXX)' STATIC_STDCPLUS=$(STATIC_STDCPLUS) + +tags: notags + $(CTAGS) $(TAGS_FILES) + +notags: + -$(DEL) tags + +clean: + -$(DEL) $(OUTDIR)$(DIRSLASH)*.o + -$(DEL) $(OUTDIR)$(DIRSLASH)*.res + -$(DEL) $(OUTDIR)$(DIRSLASH)pathdef.c + -rmdir $(OUTDIR) + -$(DEL) $(MAIN_TARGET) vimrun.exe install.exe uninstall.exe + -$(DEL) *.map +ifdef PERL + -$(DEL) if_perl.c + -$(DEL) auto$(DIRSLASH)if_perl.c +endif +ifdef MZSCHEME + -$(DEL) mzscheme_base.c +endif + $(MAKE) -C GvimExt -f Make_ming.mak clean + $(MAKE) -C xxd -f Make_ming.mak clean + $(MAKE) -C tee -f Make_ming.mak clean + +# Run vim script to generate the Ex command lookup table. +# This only needs to be run when a command name has been added or changed. +# If this fails because you don't have Vim yet, first build and install Vim +# without changes. +cmdidxs: ex_cmds.h + vim --clean -N -X --not-a-term -u create_cmdidxs.vim -c quit + +# Run vim script to generate the normal/visual mode command lookup table. +# This only needs to be run when a new normal/visual mode command has been +# added. If this fails because you don't have Vim yet: +# - change nv_cmds[] in nv_cmds.h to add the new normal/visual mode command. +# - run "make nvcmdidxs" to generate nv_cmdidxs.h +nvcmdidxs: nv_cmds.h + $(CC) $(CFLAGS) -o create_nvcmdidxs.exe create_nvcmdidxs.c $(LIB) + vim --clean -N -X --not-a-term -u create_nvcmdidxs.vim -c quit + -$(DEL) create_nvcmdidxs.exe + +########################################################################### +INCL = vim.h alloc.h ascii.h ex_cmds.h feature.h errors.h globals.h \ + keymap.h macros.h option.h os_dos.h os_win32.h proto.h regexp.h \ + spell.h structs.h termdefs.h beval.h $(NBDEBUG_INCL) +GUI_INCL = gui.h +ifeq ($(DIRECTX),yes) +GUI_INCL += gui_dwrite.h +endif +CUI_INCL = iscygpty.h + +PATHDEF_SRC = $(OUTDIR)/pathdef.c + +$(OUTDIR)/if_python.o: if_python.c if_py_both.h $(INCL) + $(CC) -c $(CFLAGS) $(PYTHONINC) $(PYTHON_HOME_DEF) $< -o $@ + +$(OUTDIR)/if_python3.o: if_python3.c if_py_both.h $(INCL) + $(CC) -c $(CFLAGS) $(PYTHON3INC) $(PYTHON3_HOME_DEF) $< -o $@ + +$(OUTDIR)/%.o : %.c $(INCL) + $(CC) -c $(CFLAGS) $< -o $@ + +ifeq ($(VIMDLL),yes) +$(OUTDIR)/vimresc.o: vim.rc vim.manifest version.h gui_w32_rc.h vim.ico + $(WINDRES) $(WINDRES_FLAGS) $(DEFINES) -UFEAT_GUI_MSWIN \ + --input-format=rc --output-format=coff -i vim.rc -o $@ + +$(OUTDIR)/vimresg.o: vim.rc vim.manifest version.h gui_w32_rc.h vim.ico + $(WINDRES) $(WINDRES_FLAGS) $(DEFINES) \ + --input-format=rc --output-format=coff -i vim.rc -o $@ + +$(OUTDIR)/vimresd.o: vim.rc version.h gui_w32_rc.h \ + tools.bmp tearoff.bmp vim.ico vim_error.ico \ + vim_alert.ico vim_info.ico vim_quest.ico + $(WINDRES) $(WINDRES_FLAGS) $(DEFINES) -DRCDLL -DVIMDLLBASE=\\\"$(VIMDLLBASE)\\\" \ + --input-format=rc --output-format=coff -i vim.rc -o $@ +else +$(OUTDIR)/vimres.o: vim.rc vim.manifest version.h gui_w32_rc.h \ + tools.bmp tearoff.bmp vim.ico vim_error.ico \ + vim_alert.ico vim_info.ico vim_quest.ico + $(WINDRES) $(WINDRES_FLAGS) $(DEFINES) \ + --input-format=rc --output-format=coff -i vim.rc -o $@ +endif + +$(OUTDIR): + $(MKDIR) $(OUTDIR) + +$(OUTDIR)/buffer.o: buffer.c $(INCL) version.h + +$(OUTDIR)/evalfunc.o: evalfunc.c $(INCL) version.h + +$(OUTDIR)/evalvars.o: evalvars.c $(INCL) version.h + +$(OUTDIR)/ex_cmds.o: ex_cmds.c $(INCL) version.h + +$(OUTDIR)/ex_cmds2.o: ex_cmds2.c $(INCL) version.h + +$(OUTDIR)/ex_docmd.o: ex_docmd.c $(INCL) ex_cmdidxs.h + +$(OUTDIR)/hardcopy.o: hardcopy.c $(INCL) version.h + +$(OUTDIR)/misc1.o: misc1.c $(INCL) version.h + +$(OUTDIR)/normal.o: normal.c $(INCL) nv_cmdidxs.h nv_cmds.h + +$(OUTDIR)/netbeans.o: netbeans.c $(INCL) version.h + +$(OUTDIR)/version.o: version.c $(INCL) version.h + +$(OUTDIR)/vim9class.o: vim9class.c $(INCL) vim9.h + +$(OUTDIR)/vim9cmds.o: vim9cmds.c $(INCL) vim9.h + +$(OUTDIR)/vim9compile.o: vim9compile.c $(INCL) vim9.h + +$(OUTDIR)/vim9execute.o: vim9execute.c $(INCL) vim9.h + +$(OUTDIR)/vim9expr.o: vim9expr.c $(INCL) vim9.h + +$(OUTDIR)/vim9instr.o: vim9instr.c $(INCL) vim9.h + +$(OUTDIR)/vim9script.o: vim9script.c $(INCL) vim9.h + +$(OUTDIR)/vim9type.o: vim9type.c $(INCL) vim9.h + +$(OUTDIR)/viminfo.o: viminfo.c $(INCL) version.h + +$(OUTDIR)/gui_dwrite.o: gui_dwrite.cpp gui_dwrite.h + $(CC) -c $(CFLAGS) $(CXXFLAGS) gui_dwrite.cpp -o $@ + +$(OUTDIR)/gui.o: gui.c $(INCL) $(GUI_INCL) + $(CC) -c $(CFLAGS) gui.c -o $@ + +$(OUTDIR)/beval.o: beval.c $(INCL) $(GUI_INCL) + $(CC) -c $(CFLAGS) beval.c -o $@ + +$(OUTDIR)/gui_beval.o: gui_beval.c $(INCL) $(GUI_INCL) + $(CC) -c $(CFLAGS) gui_beval.c -o $@ + +$(OUTDIR)/gui_w32.o: gui_w32.c $(INCL) $(GUI_INCL) version.h + $(CC) -c $(CFLAGS) gui_w32.c -o $@ + +$(OUTDIR)/if_cscope.o: if_cscope.c $(INCL) + $(CC) -c $(CFLAGS) if_cscope.c -o $@ + +$(OUTDIR)/if_mzsch.o: if_mzsch.c $(INCL) $(MZSCHEME_INCL) $(MZ_EXTRA_DEP) + $(CC) -c $(CFLAGS) if_mzsch.c -o $@ + +mzscheme_base.c: + $(MZSCHEME)/mzc --c-mods mzscheme_base.c ++lib scheme/base + +# Remove -D__IID_DEFINED__ for newer versions of the w32api +$(OUTDIR)/if_ole.o: if_ole.cpp $(INCL) if_ole.h + $(CC) -c $(CFLAGS) $(CXXFLAGS) if_ole.cpp -o $@ + +auto/if_perl.c: if_perl.xs typemap + $(XSUBPP) -prototypes -typemap \ + $(PERLTYPEMAP) if_perl.xs -output $@ + +$(OUTDIR)/if_perl.o: auto/if_perl.c $(INCL) + $(CC) -c $(CFLAGS) auto/if_perl.c -o $@ + + +$(OUTDIR)/if_ruby.o: if_ruby.c $(INCL) version.h +ifeq (16, $(RUBY)) + $(CC) $(CFLAGS) -U_WIN32 -c -o $@ if_ruby.c +endif + +$(OUTDIR)/iscygpty.o: iscygpty.c $(CUI_INCL) + $(CC) -c $(CFLAGS) iscygpty.c -o $@ + +$(OUTDIR)/main.o: main.c $(INCL) $(CUI_INCL) + $(CC) -c $(CFLAGS) main.c -o $@ + +$(OUTDIR)/netbeans.o: netbeans.c $(INCL) $(NBDEBUG_INCL) $(NBDEBUG_SRC) + $(CC) -c $(CFLAGS) netbeans.c -o $@ + +$(OUTDIR)/os_w32exec.o: os_w32exe.c $(INCL) + $(CC) -c $(CFLAGS) -UFEAT_GUI_MSWIN os_w32exe.c -o $@ + +$(OUTDIR)/os_w32exeg.o: os_w32exe.c $(INCL) + $(CC) -c $(CFLAGS) os_w32exe.c -o $@ + +$(OUTDIR)/os_win32.o: os_win32.c $(INCL) $(MZSCHEME_INCL) + $(CC) -c $(CFLAGS) os_win32.c -o $@ + +$(OUTDIR)/regexp.o: regexp.c regexp_bt.c regexp_nfa.c $(INCL) + $(CC) -c $(CFLAGS) regexp.c -o $@ + +$(OUTDIR)/register.o: register.c $(INCL) + $(CC) -c $(CFLAGS) register.c -o $@ + +$(OUTDIR)/terminal.o: terminal.c $(INCL) $(TERM_DEPS) + $(CC) -c $(CFLAGS) terminal.c -o $@ + +$(OUTDIR)/pathdef.o: $(PATHDEF_SRC) $(INCL) + $(CC) -c $(CFLAGS) $(PATHDEF_SRC) -o $@ + + +CCCTERM = $(CC) -c $(CFLAGS) -Ilibvterm/include -DINLINE="" \ + -DVSNPRINTF=vim_vsnprintf \ + -DSNPRINTF=vim_snprintf \ + -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ + -DWCWIDTH_FUNCTION=utf_uint2cells \ + -DGET_SPECIAL_PTY_TYPE_FUNCTION=get_special_pty_type + +$(OUTDIR)/vterm_%.o : libvterm/src/%.c $(TERM_DEPS) + $(CCCTERM) $< -o $@ + + +$(OUTDIR)/%.o : xdiff/%.c $(XDIFF_DEPS) + $(CC) -c $(CFLAGS) $< -o $@ + + +$(PATHDEF_SRC): Make_cyg_ming.mak Make_cyg.mak Make_ming.mak | $(OUTDIR) +ifneq (sh.exe, $(SHELL)) + @echo creating $(PATHDEF_SRC) + @echo '/* pathdef.c */' > $(PATHDEF_SRC) + @echo '#include "vim.h"' >> $(PATHDEF_SRC) + @echo 'char_u *default_vim_dir = (char_u *)"$(VIMRCLOC)";' >> $(PATHDEF_SRC) + @echo 'char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR)";' >> $(PATHDEF_SRC) + @echo 'char_u *all_cflags = (char_u *)"$(CC) $(CFLAGS)";' >> $(PATHDEF_SRC) + @echo 'char_u *all_lflags = (char_u *)"$(LINK) $(CFLAGS) $(LFLAGS) -o $(TARGET) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB)";' >> $(PATHDEF_SRC) + @echo 'char_u *compiled_user = (char_u *)"$(USERNAME)";' >> $(PATHDEF_SRC) + @echo 'char_u *compiled_sys = (char_u *)"$(USERDOMAIN)";' >> $(PATHDEF_SRC) +else + @echo creating $(PATHDEF_SRC) + @echo /* pathdef.c */ > $(PATHDEF_SRC) + @echo #include "vim.h" >> $(PATHDEF_SRC) + @echo char_u *default_vim_dir = (char_u *)"$(VIMRCLOC)"; >> $(PATHDEF_SRC) + @echo char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR)"; >> $(PATHDEF_SRC) + @echo char_u *all_cflags = (char_u *)"$(CC) $(CFLAGS)"; >> $(PATHDEF_SRC) + @echo char_u *all_lflags = (char_u *)"$(CC) $(CFLAGS) $(LFLAGS) -o $(TARGET) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB)"; >> $(PATHDEF_SRC) + @echo char_u *compiled_user = (char_u *)"$(USERNAME)"; >> $(PATHDEF_SRC) + @echo char_u *compiled_sys = (char_u *)"$(USERDOMAIN)"; >> $(PATHDEF_SRC) +endif + +# vim: set noet sw=8 ts=8 sts=0 wm=0 tw=0: diff --git a/src/Make_ming.mak b/src/Make_ming.mak new file mode 100644 index 0000000..e9e20f6 --- /dev/null +++ b/src/Make_ming.mak @@ -0,0 +1,51 @@ +# +# Makefile for VIM on Win32, using MinGW +# +# Also read INSTALLpc.txt! +# +# The old Make_ming.mak (maintained by Ron Aaron et al.) was merged into +# Make_cyg_ming.mak. +# This file contains MinGW specific settings. Common settings are contained +# in Make_cyg_ming.mak. +# +# Last updated by Ken Takata. +# Last Change: 2014 Oct 21 + + +# uncomment 'PERL' if you want a perl-enabled version +#PERL=c:/perl + +# uncomment 'LUA' if you want a Lua-enabled version +#LUA=c:/lua + +# uncomment 'MZSCHEME' if you want a MzScheme-enabled version +#MZSCHEME=d:/plt + +# uncomment 'PYTHON' if you want a python-enabled version +# Put the path to the python distro here. If cross compiling from Linux, you +# will also need to convert the header files to unix instead of dos format: +# for fil in *.h ; do vim -e -c 'set ff=unix|w|q' $fil +# and also, you will need to make a mingw32 'libpython20.a' to link with: +# cd $PYTHON/libs +# pexports python20.dll > python20.def +# dlltool -d python20.def -l libpython20.a +# on my Linux box, I put the Python stuff here: +#PYTHON=/home/ron/ActivePython-2.0.0-202/src/Core +# on my NT box, it's here: +#PYTHON=c:/python20 + +# uncomment 'PYTHON3' if you want a python3-enabled version +#PYTHON3=c:/python31 + +# uncomment 'TCL' if you want a Tcl-enabled version +#TCL=c:/tcl + +# uncomment 'RUBY' if you want a Ruby-enabled version +#RUBY=c:/ruby + + +# Do not change this. +UNDER_CYGWIN = no +include Make_cyg_ming.mak + +# vim: set noet sw=8 ts=8 sts=0 wm=0 tw=0: diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak new file mode 100644 index 0000000..f98d905 --- /dev/null +++ b/src/Make_mvc.mak @@ -0,0 +1,1946 @@ +# Makefile for Vim on Win32 (Windows 7/8/10/11) and Win64, using the Microsoft +# Visual C++ compilers. Known to work with VC14 (VS2015), VC14.1 (VS2017), +# VC14.2 (VS2019) and VC14.3 (VS2022). +# +# To build using other Windows compilers, see INSTALLpc.txt +# +# This makefile can build the console, GUI, OLE-enable, Perl-enabled and +# Python-enabled versions of Vim for Win32 platforms. +# +# The basic command line to build Vim is: +# +# nmake -f Make_mvc.mak +# +# This will build the console version of Vim with no additional interfaces. +# To add features, define any of the following: +# +# !!!! After changing any features do "nmake clean" first !!!! +# +# Feature Set: FEATURES=[TINY, NORMAL, HUGE] (default is HUGE) +# +# Name to add to the version: MODIFIED_BY=[name of modifier] +# +# GUI interface: GUI=yes (default is no) +# +# GUI with DirectWrite (DirectX): DIRECTX=yes +# (default is yes if GUI=yes, requires GUI=yes) +# +# Color emoji support: COLOR_EMOJI=yes +# (default is yes if DIRECTX=yes, requires WinSDK 8.1 or later.) +# +# OLE interface: OLE=yes (usually with GUI=yes) +# +# IME support: IME=yes (default is yes) +# DYNAMIC_IME=[yes or no] (to load the imm32.dll dynamically, default +# is yes) +# +# Terminal support: TERMINAL=yes (default is yes if FEATURES is HUGE) +# Will also enable CHANNEL +# +# Sound support: SOUND=yes (default is yes) +# +# Sodium support: SODIUM=[Path to Sodium directory] +# DYNAMIC_SODIUM=yes (to load the Sodium DLL dynamically) +# You need to install the msvc package from +# https://download.libsodium.org/libsodium/releases/ +# and package the libsodium.dll with Vim +# +# +# DLL support (EXPERIMENTAL): VIMDLL=yes (default is no) +# Creates vim{32,64}.dll, and stub gvim.exe and vim.exe. +# The shared codes between the GUI and the console are built into +# the DLL. This reduces the total file size and memory usage. +# Also supports `vim -g` and the `:gui` command. +# +# Lua interface: +# LUA=[Path to Lua directory] +# DYNAMIC_LUA=yes (to load the Lua DLL dynamically) +# LUA_VER=[Lua version] (default is 53) +# +# MzScheme interface: +# MZSCHEME=[Path to MzScheme directory] +# DYNAMIC_MZSCHEME=yes (to load the MzScheme DLLs dynamically) +# MZSCHEME_VER=[MzScheme version] (default is 3m_a0solc (6.6)) +# Used for the DLL file name. E.g.: +# C:\Program Files (x86)\Racket\lib\libracket3m_XXXXXX.dll +# MZSCHEME_DEBUG=no +# +# Perl interface: +# PERL=[Path to Perl directory] +# DYNAMIC_PERL=yes (to load the Perl DLL dynamically) +# PERL_VER=[Perl version, in the form 55 (5.005), 56 (5.6.x), +# 510 (5.10.x), etc] +# (default is 524) +# +# Python interface: +# PYTHON=[Path to Python directory] +# DYNAMIC_PYTHON=yes (to load the Python DLL dynamically) +# PYTHON_VER=[Python version, eg 22, 23, ..., 27] (default is 27) +# +# Python3 interface: +# PYTHON3=[Path to Python3 directory] +# DYNAMIC_PYTHON3=yes (to load the Python3 DLL dynamically) +# PYTHON3_VER=[Python3 version, eg 30, 31] (default is 36) +# +# Ruby interface: +# RUBY=[Path to Ruby directory] +# DYNAMIC_RUBY=yes (to load the Ruby DLL dynamically) +# RUBY_VER=[Ruby version, eg 19, 22] (default is 22) +# RUBY_API_VER_LONG=[Ruby API version, eg 1.9.1, 2.2.0] +# (default is 2.2.0) +# You must set RUBY_API_VER_LONG when change RUBY_VER. +# Note: If you use Ruby 1.9.3, set as follows: +# RUBY_VER=19 +# RUBY_API_VER_LONG=1.9.1 (not 1.9.3, because the API version is 1.9.1.) +# +# Tcl interface: +# TCL=[Path to Tcl directory] +# DYNAMIC_TCL=yes (to load the Tcl DLL dynamically) +# TCL_VER=[Tcl version, e.g. 80, 83] (default is 86) +# TCL_VER_LONG=[Tcl version, eg 8.3] (default is 8.6) +# You must set TCL_VER_LONG when you set TCL_VER. +# TCL_DLL=[Tcl dll name, e.g. tcl86.dll] (default is tcl86.dll) +# +# Cscope support: CSCOPE=yes +# +# Iconv library support (always dynamically loaded): +# ICONV=[yes or no] (default is yes) +# +# Intl library support (always dynamically loaded): +# GETTEXT=[yes or no] (default is yes) +# See http://sourceforge.net/projects/gettext/ +# +# PostScript printing: POSTSCRIPT=yes (default is no) +# +# Netbeans Support: NETBEANS=[yes or no] (default is yes if GUI is yes) +# Requires CHANNEL. +# +# Netbeans Debugging Support: NBDEBUG=[yes or no] (should be no, yes +# doesn't work) +# +# Inter process communication: CHANNEL=[yes or no] (default is yes if GUI +# is yes or TERMINAL is yes) +# +# XPM Image Support: XPM=[path to XPM directory] +# Default is "xpm", using the files included in the distribution. +# Use "no" to disable this feature. +# +# Optimization: OPTIMIZE=[SPACE, SPEED, MAXSPEED] (default is MAXSPEED) +# +# Processor Version: CPUNR=[any, i686, sse, sse2, avx, avx2] (default is +# sse2) +# avx is available on Visual C++ 2010 and after. +# avx2 is available on Visual C++ 2013 Update 2 and after. +# +# Version Support: WINVER=[0x0601, 0x0602, 0x0603, 0x0A00] (default is +# 0x0601) +# Supported versions depends on your target SDK, check SDKDDKVer.h +# See https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt +# +# Debug version: DEBUG=yes +# Mapfile: MAP=[no, yes or lines] (default is yes) +# no: Don't write a mapfile. +# yes: Write a normal mapfile. +# lines: Write a mapfile with line numbers (only for VC6 and later) +# +# Static Code Analysis: ANALYZE=yes (works with VS2012 or later) +# +# Address Sanitizer: ASAN=yes (works with VS2019 or later) +# +# You can combine any of these interfaces +# +# Example: To build the non-debug, GUI version with Perl interface: +# nmake -f Make_mvc.mak GUI=yes PERL=C:\Perl + +### See feature.h for a list of optionals. +# If you want to build some optional features without modifying the source, +# you can set DEFINES on the command line, e.g., +# nmake -f Make_mvc.mvc "DEFINES=-DEMACS_TAGS" + +# Build on Windows NT/XP + +TARGETOS = WINNT + +!if "$(VIMDLL)" == "yes" +GUI = yes +!endif + +!ifndef DIRECTX +DIRECTX = $(GUI) +!endif + +# Select a code directory, depends on GUI, OLE, DEBUG, interfaces and etc. +# If you change something else, do "make clean" first! +!if "$(VIMDLL)" == "yes" +OBJDIR = .\ObjD +!elseif "$(GUI)" == "yes" +OBJDIR = .\ObjG +!else +OBJDIR = .\ObjC +!endif +!if "$(DIRECTX)" == "yes" && "$(GUI)" == "yes" +OBJDIR = $(OBJDIR)X +!endif +!if "$(OLE)" == "yes" +OBJDIR = $(OBJDIR)O +!endif +!ifdef LUA +OBJDIR = $(OBJDIR)U +!endif +!ifdef PERL +OBJDIR = $(OBJDIR)L +!endif +!ifdef PYTHON +OBJDIR = $(OBJDIR)Y +!endif +!ifdef PYTHON3 +OBJDIR = $(OBJDIR)H +!endif +!ifdef TCL +OBJDIR = $(OBJDIR)T +!endif +!ifdef RUBY +OBJDIR = $(OBJDIR)R +!endif +!ifdef MZSCHEME +OBJDIR = $(OBJDIR)Z +!endif +!ifdef USE_MSVCRT +OBJDIR = $(OBJDIR)V +!endif +!if "$(DEBUG)" == "yes" +OBJDIR = $(OBJDIR)d +!endif + +!ifdef PROCESSOR_ARCHITECTURE +# We're on Windows NT or using VC 6+ +! ifdef CPU +ASSEMBLY_ARCHITECTURE=$(CPU) +# Using I386 for $ASSEMBLY_ARCHITECTURE doesn't work for VC7. +! if "$(CPU)" == "I386" +CPU = i386 +! endif +! else # !CPU +CPU = i386 +! ifndef PLATFORM +! ifdef TARGET_CPU +PLATFORM = $(TARGET_CPU) +! elseif defined(VSCMD_ARG_TGT_ARCH) +PLATFORM = $(VSCMD_ARG_TGT_ARCH) +! endif +! endif +! ifdef PLATFORM +! if ("$(PLATFORM)" == "x64") || ("$(PLATFORM)" == "X64") +CPU = AMD64 +! elseif ("$(PLATFORM)" == "arm64") || ("$(PLATFORM)" == "ARM64") +CPU = ARM64 +! elseif ("$(PLATFORM)" != "x86") && ("$(PLATFORM)" != "X86") +! error *** ERROR Unknown target platform "$(PLATFORM)". Make aborted. +! endif +! endif # !PLATFORM +! endif +!else # !PROCESSOR_ARCHITECTURE +# We're on Windows 95 +CPU = i386 +!endif # !PROCESSOR_ARCHITECTURE +ASSEMBLY_ARCHITECTURE=$(CPU) +OBJDIR = $(OBJDIR)$(CPU) + +# Build a retail version by default + +!if "$(DEBUG)" != "yes" +NODEBUG = 1 +!else +! undef NODEBUG +MAKEFLAGS_GVIMEXT = DEBUG=yes +!endif + +LINK = link + +# Check VC version. +!if [echo MSVCVER=_MSC_VER> msvcver.c && $(CC) /EP msvcver.c > msvcver.~ 2> nul] +! message *** ERROR +! message Cannot run Visual C to determine its version. Make sure cl.exe is in your PATH. +! message This can usually be done by running "vcvarsall.bat", located in the bin directory where Visual Studio was installed. +! error Make aborted. +!else +! include msvcver.~ +! if [del msvcver.c msvcver.~] +! endif +!endif + +!if $(MSVCVER) < 1900 +! message *** ERROR +! message Unsupported MSVC version. +! message Please use Visual C++ 2015 or later. +! error Make aborted. +!endif + +MSVC_MAJOR = ($(MSVCVER) / 100 - 5) +MSVCRT_VER = ($(MSVCVER) / 100 * 10 - 50) + +# Calculate MSVC_FULL. +!if [echo MSVC_FULL=_MSC_FULL_VER> msvcfullver.c && $(CC) /EP msvcfullver.c > msvcfullver.~ 2> nul] +! message *** ERROR +! message Cannot run Visual C to determine its version. Make sure cl.exe is in your PATH. +! message This can usually be done by running "vcvarsall.bat", located in the bin directory where Visual Studio was installed. +! error Make aborted. +!else +! include msvcfullver.~ +! if [del msvcfullver.c msvcfullver.~] +! endif +!endif + + +# Calculate MSVCRT_VER +!if [(set /a MSVCRT_VER="$(MSVCRT_VER)" > nul) && set MSVCRT_VER > msvcrtver.~] == 0 +! include msvcrtver.~ +! if [del msvcrtver.~] +! endif +!endif + +# Base name of the msvcrXX.dll (vcruntimeXXX.dll) +MSVCRT_NAME = vcruntime$(MSVCRT_VER) + +### Set the default $(WINVER) to make it work with Windows 7 +!ifndef WINVER +WINVER = 0x0601 +!endif + +# Use multiprocess build +USE_MP = yes + +!if "$(FEATURES)"=="" +FEATURES = HUGE +!endif + +!ifndef CTAGS +# this assumes ctags is Exuberant ctags +CTAGS = ctags -I INIT+,INIT2+,INIT3+,INIT4+,INIT5+ --fields=+S +!endif + +!ifndef CSCOPE +CSCOPE = yes +!endif + +!if "$(CSCOPE)" == "yes" +# CSCOPE - Include support for Cscope +CSCOPE_DEFS = -DFEAT_CSCOPE +!endif + +!ifndef TERMINAL +! if "$(FEATURES)"=="HUGE" +TERMINAL = yes +! else +TERMINAL = no +! endif +!endif + +!if "$(TERMINAL)" == "yes" +TERM_OBJ = \ + $(OBJDIR)/terminal.obj \ + $(OBJDIR)/vterm_encoding.obj \ + $(OBJDIR)/vterm_keyboard.obj \ + $(OBJDIR)/vterm_mouse.obj \ + $(OBJDIR)/vterm_parser.obj \ + $(OBJDIR)/vterm_pen.obj \ + $(OBJDIR)/vterm_screen.obj \ + $(OBJDIR)/vterm_state.obj \ + $(OBJDIR)/vterm_unicode.obj \ + $(OBJDIR)/vterm_vterm.obj +TERM_DEFS = -DFEAT_TERMINAL +TERM_DEPS = \ + libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h \ + libvterm/src/rect.h \ + libvterm/src/utf8.h \ + libvterm/src/vterm_internal.h +!endif + +!ifndef SOUND +! if "$(FEATURES)"=="HUGE" +SOUND = yes +! else +SOUND = no +! endif +!endif + +!ifndef SODIUM +SODIUM = no +!endif +!ifndef DYNAMIC_SODIUM +DYNAMIC_SODIUM = yes +!endif + +!if "$(SODIUM)" != "no" +! if "$(CPU)" == "AMD64" +SOD_LIB = $(SODIUM)\x64\Release\v140\dynamic +! elseif "$(CPU)" == "i386" +SOD_LIB = $(SODIUM)\Win32\Release\v140\dynamic +! else +SODIUM = no +! endif +!endif + +!if "$(SODIUM)" != "no" +SOD_INC = /I "$(SODIUM)\include" +! if "$(DYNAMIC_SODIUM)" == "yes" +SODIUM_DLL = libsodium.dll +SOD_DEFS = -DHAVE_SODIUM -DDYNAMIC_SODIUM -DDYNAMIC_SODIUM_DLL=\"$(SODIUM_DLL)\" +SOD_LIB = +! else +SOD_DEFS = -DHAVE_SODIUM +SOD_LIB = $(SOD_LIB)\libsodium.lib +! endif +!endif + +!ifndef NETBEANS +NETBEANS = $(GUI) +!endif + +!ifndef CHANNEL +! if "$(FEATURES)"=="HUGE" || "$(TERMINAL)"=="yes" +CHANNEL = yes +! else +CHANNEL = $(GUI) +! endif +!endif + +# GUI specific features. +!if "$(GUI)" == "yes" +# Only allow NETBEANS for a GUI build and CHANNEL. +! if "$(NETBEANS)" == "yes" && "$(CHANNEL)" == "yes" +# NETBEANS - Include support for Netbeans integration +NETBEANS_PRO = proto/netbeans.pro +NETBEANS_OBJ = $(OBJDIR)/netbeans.obj +NETBEANS_DEFS = -DFEAT_NETBEANS_INTG + +! if "$(NBDEBUG)" == "yes" +NBDEBUG_DEFS = -DNBDEBUG +NBDEBUG_INCL = nbdebug.h +NBDEBUG_SRC = nbdebug.c +! endif +NETBEANS_LIB = WSock32.lib +! endif + +# DirectWrite (DirectX) +! if "$(DIRECTX)" == "yes" +DIRECTX_DEFS = -DFEAT_DIRECTX -DDYNAMIC_DIRECTX +! if "$(COLOR_EMOJI)" != "no" +DIRECTX_DEFS = $(DIRECTX_DEFS) -DFEAT_DIRECTX_COLOR_EMOJI +! endif +DIRECTX_INCL = gui_dwrite.h +DIRECTX_OBJ = $(OUTDIR)\gui_dwrite.obj +! endif + +# Only allow XPM for a GUI build. +! ifndef XPM +! ifndef USE_MSVCRT +# Both XPM and USE_MSVCRT are not set, use the included xpm files, depending +# on the architecture. +! if "$(CPU)" == "AMD64" +XPM = xpm\x64 +! elseif "$(CPU)" == "ARM64" +XPM = xpm\arm64 +! elseif "$(CPU)" == "i386" +XPM = xpm\x86 +! else +XPM = no +! endif +! else # USE_MSVCRT +XPM = no +! endif # USE_MSVCRT +! endif # XPM +! if "$(XPM)" != "no" +# XPM - Include support for XPM signs +# See the xpm directory for more information. +XPM_OBJ = $(OBJDIR)/xpm_w32.obj +XPM_DEFS = -DFEAT_XPM_W32 +XPM_LIB = $(XPM)\lib-vc14\libXpm.lib +XPM_INC = -I $(XPM)\include -I $(XPM)\..\include +! endif +!endif # GUI + +!if "$(SOUND)" == "yes" +SOUND_PRO = proto/sound.pro +SOUND_OBJ = $(OBJDIR)/sound.obj +SOUND_DEFS = -DFEAT_SOUND +SOUND_LIB = winmm.lib +!endif + +!if "$(CHANNEL)" == "yes" +CHANNEL_PRO = proto/job.pro proto/channel.pro +CHANNEL_OBJ = $(OBJDIR)/job.obj $(OBJDIR)/channel.obj +CHANNEL_DEFS = -DFEAT_JOB_CHANNEL -DFEAT_IPV6 -DHAVE_INET_NTOP + +NETBEANS_LIB = WSock32.lib Ws2_32.lib +!endif + +# need advapi32.lib for GetUserName() +# need shell32.lib for ExtractIcon() +# need netapi32.lib for NetUserEnum() +# gdi32.lib and comdlg32.lib for printing support +# ole32.lib and uuid.lib are needed for FEAT_SHORTCUT +CON_LIB = oldnames.lib kernel32.lib advapi32.lib shell32.lib gdi32.lib \ + comdlg32.lib ole32.lib netapi32.lib uuid.lib user32.lib \ + /machine:$(CPU) +!if "$(DELAYLOAD)" == "yes" +CON_LIB = $(CON_LIB) /DELAYLOAD:comdlg32.dll /DELAYLOAD:ole32.dll DelayImp.lib +!endif + +# If you have a fixed directory for $VIM or $VIMRUNTIME, other than the normal +# default, use these lines. +#VIMRCLOC = somewhere +#VIMRUNTIMEDIR = somewhere + +CFLAGS = -c /W3 /GF /nologo -I. -Iproto -DHAVE_PATHDEF -DWIN32 -DHAVE_STDINT_H \ + $(CSCOPE_DEFS) $(TERM_DEFS) $(SOUND_DEFS) $(NETBEANS_DEFS) $(CHANNEL_DEFS) \ + $(NBDEBUG_DEFS) $(XPM_DEFS) $(SOD_DEFS) $(SOD_INC) \ + $(DEFINES) -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER) \ + /source-charset:utf-8 + +#>>>>> end of choices +########################################################################### + +DEL_TREE = rmdir /s /q + +INTDIR=$(OBJDIR) +OUTDIR=$(OBJDIR) + +### Validate CPUNR +!ifndef CPUNR +# default to SSE2 +CPUNR = sse2 +!elseif "$(CPUNR)" == "i386" || "$(CPUNR)" == "i486" || "$(CPUNR)" == "i586" +# alias i386, i486 and i586 to i686 +! message *** WARNING CPUNR=$(CPUNR) is not a valid target architecture. +! message Windows 7 is the minimum target OS, with a minimum target +! message architecture of i686. +! message Retargeting to i686 +CPUNR = i686 +!elseif "$(CPUNR)" == "pentium4" +# alias pentium4 to sse2 +! message *** WARNING CPUNR=pentium4 is deprecated in favour of sse2. +! message Retargeting to sse2. +CPUNR = sse2 +!elseif "$(CPUNR)" != "any" && "$(CPUNR)" != "i686" && "$(CPUNR)" != "sse" && "$(CPUNR)" != "sse2" && "$(CPUNR)" != "avx" && "$(CPUNR)" != "avx2" +! error *** ERROR Unknown target architecture "$(CPUNR)". Make aborted. +!endif + +# Convert processor ID to MVC-compatible number +# IA32/SSE/SSE2 are only supported on x86 +!if "$(ASSEMBLY_ARCHITECTURE)" == "i386" && ("$(CPUNR)" == "i686" || "$(CPUNR)" == "any") +CPUARG = /arch:IA32 +!elseif "$(ASSEMBLY_ARCHITECTURE)" == "i386" && "$(CPUNR)" == "sse" +CPUARG = /arch:SSE +!elseif "$(ASSEMBLY_ARCHITECTURE)" == "i386" && "$(CPUNR)" == "sse2" +CPUARG = /arch:SSE2 +!elseif "$(CPUNR)" == "avx" +CPUARG = /arch:AVX +!elseif "$(CPUNR)" == "avx2" +CPUARG = /arch:AVX2 +!endif + +# Pass CPUARG to GvimExt, to avoid using version-dependent defaults +MAKEFLAGS_GVIMEXT = $(MAKEFLAGS_GVIMEXT) CPUARG="$(CPUARG)" + +!if "$(VIMDLL)" == "yes" +VIMDLLBASE = vim +! if "$(ASSEMBLY_ARCHITECTURE)" == "i386" +VIMDLLBASE = $(VIMDLLBASE)32 +! else +VIMDLLBASE = $(VIMDLLBASE)64 +! endif +! if "$(DEBUG)" == "yes" +VIMDLLBASE = $(VIMDLLBASE)d +! endif +!endif + +LIBC = +DEBUGINFO = /Zi + +# Use multiprocess build. +!if "$(USE_MP)" == "yes" +CFLAGS = $(CFLAGS) /MP +!endif + +# Use static code analysis +!if "$(ANALYZE)" == "yes" +CFLAGS = $(CFLAGS) /analyze +!endif + +# Address Sanitizer (ASAN) generally available starting with VS2019 version +# 16.9 +!if ("$(ASAN)" == "yes") && ($(MSVC_FULL) >= 192829913) +CFLAGS = $(CFLAGS) /fsanitize=address +!endif + +!ifdef NODEBUG + +VIM = vim +! if "$(OPTIMIZE)" == "SPACE" +OPTFLAG = /O1 +! elseif "$(OPTIMIZE)" == "SPEED" +OPTFLAG = /O2 +! else # MAXSPEED +OPTFLAG = /Ox +! endif + +# Use link time code generation if not worried about size +! if "$(OPTIMIZE)" != "SPACE" +OPTFLAG = $(OPTFLAG) /GL +! endif + +CFLAGS = $(CFLAGS) $(OPTFLAG) -DNDEBUG $(CPUARG) +RCFLAGS = -DNDEBUG +! ifdef USE_MSVCRT +CFLAGS = $(CFLAGS) /MD +LIBC = msvcrt.lib +! else +CFLAGS = $(CFLAGS) /Zl /MT +LIBC = libcmt.lib +! endif + +!else # DEBUG + +VIM = vimd +! if ("$(CPU)" == "i386") || ("$(CPU)" == "ix86") +DEBUGINFO = /ZI +! endif +CFLAGS = $(CFLAGS) -D_DEBUG -DDEBUG /Od +RCFLAGS = -D_DEBUG -DDEBUG +# The /fixed:no is needed for Quantify. +LIBC = /fixed:no +! ifdef USE_MSVCRT +CFLAGS = $(CFLAGS) /MDd +LIBC = $(LIBC) msvcrtd.lib +! else +CFLAGS = $(CFLAGS) /Zl /MTd +LIBC = $(LIBC) libcmtd.lib +! endif + +!endif # DEBUG + +# Visual Studio 2005 has 'deprecated' many of the standard CRT functions +CFLAGS_DEPR = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE +CFLAGS = $(CFLAGS) $(CFLAGS_DEPR) + +!include Make_all.mak +!include testdir\Make_all.mak + +INCL = vim.h alloc.h ascii.h ex_cmds.h feature.h errors.h globals.h \ + keymap.h macros.h option.h os_dos.h os_win32.h proto.h regexp.h \ + spell.h structs.h termdefs.h beval.h $(NBDEBUG_INCL) + +OBJ = \ + $(OUTDIR)\alloc.obj \ + $(OUTDIR)\arabic.obj \ + $(OUTDIR)\arglist.obj \ + $(OUTDIR)\autocmd.obj \ + $(OUTDIR)\beval.obj \ + $(OUTDIR)\blob.obj \ + $(OUTDIR)\blowfish.obj \ + $(OUTDIR)\buffer.obj \ + $(OUTDIR)\bufwrite.obj \ + $(OUTDIR)\change.obj \ + $(OUTDIR)\charset.obj \ + $(OUTDIR)\cindent.obj \ + $(OUTDIR)\clientserver.obj \ + $(OUTDIR)\clipboard.obj \ + $(OUTDIR)\cmdexpand.obj \ + $(OUTDIR)\cmdhist.obj \ + $(OUTDIR)\crypt.obj \ + $(OUTDIR)\crypt_zip.obj \ + $(OUTDIR)\debugger.obj \ + $(OUTDIR)\dict.obj \ + $(OUTDIR)\diff.obj \ + $(OUTDIR)\digraph.obj \ + $(OUTDIR)\drawline.obj \ + $(OUTDIR)\drawscreen.obj \ + $(OUTDIR)\edit.obj \ + $(OUTDIR)\eval.obj \ + $(OUTDIR)\evalbuffer.obj \ + $(OUTDIR)\evalfunc.obj \ + $(OUTDIR)\evalvars.obj \ + $(OUTDIR)\evalwindow.obj \ + $(OUTDIR)\ex_cmds.obj \ + $(OUTDIR)\ex_cmds2.obj \ + $(OUTDIR)\ex_docmd.obj \ + $(OUTDIR)\ex_eval.obj \ + $(OUTDIR)\ex_getln.obj \ + $(OUTDIR)\fileio.obj \ + $(OUTDIR)\filepath.obj \ + $(OUTDIR)\findfile.obj \ + $(OUTDIR)\float.obj \ + $(OUTDIR)\fold.obj \ + $(OUTDIR)\getchar.obj \ + $(OUTDIR)\gui_xim.obj \ + $(OUTDIR)\hardcopy.obj \ + $(OUTDIR)\hashtab.obj \ + $(OUTDIR)\help.obj \ + $(OUTDIR)\highlight.obj \ + $(OUTDIR)\if_cscope.obj \ + $(OUTDIR)\indent.obj \ + $(OUTDIR)\insexpand.obj \ + $(OUTDIR)\json.obj \ + $(OUTDIR)\list.obj \ + $(OUTDIR)\locale.obj \ + $(OUTDIR)\logfile.obj \ + $(OUTDIR)\main.obj \ + $(OUTDIR)\map.obj \ + $(OUTDIR)\mark.obj \ + $(OUTDIR)\match.obj \ + $(OUTDIR)\mbyte.obj \ + $(OUTDIR)\memfile.obj \ + $(OUTDIR)\memline.obj \ + $(OUTDIR)\menu.obj \ + $(OUTDIR)\message.obj \ + $(OUTDIR)\misc1.obj \ + $(OUTDIR)\misc2.obj \ + $(OUTDIR)\mouse.obj \ + $(OUTDIR)\move.obj \ + $(OUTDIR)\normal.obj \ + $(OUTDIR)\ops.obj \ + $(OUTDIR)\option.obj \ + $(OUTDIR)\optionstr.obj \ + $(OUTDIR)\os_mswin.obj \ + $(OUTDIR)\os_win32.obj \ + $(OUTDIR)\pathdef.obj \ + $(OUTDIR)\popupmenu.obj \ + $(OUTDIR)\popupwin.obj \ + $(OUTDIR)\profiler.obj \ + $(OUTDIR)\quickfix.obj \ + $(OUTDIR)\regexp.obj \ + $(OUTDIR)\register.obj \ + $(OUTDIR)\scriptfile.obj \ + $(OUTDIR)\screen.obj \ + $(OUTDIR)\search.obj \ + $(OUTDIR)\session.obj \ + $(OUTDIR)\sha256.obj \ + $(OUTDIR)\sign.obj \ + $(OUTDIR)\spell.obj \ + $(OUTDIR)\spellfile.obj \ + $(OUTDIR)\spellsuggest.obj \ + $(OUTDIR)\strings.obj \ + $(OUTDIR)\syntax.obj \ + $(OUTDIR)\tag.obj \ + $(OUTDIR)\term.obj \ + $(OUTDIR)\testing.obj \ + $(OUTDIR)\textformat.obj \ + $(OUTDIR)\textobject.obj \ + $(OUTDIR)\textprop.obj \ + $(OUTDIR)\time.obj \ + $(OUTDIR)\typval.obj \ + $(OUTDIR)\ui.obj \ + $(OUTDIR)\undo.obj \ + $(OUTDIR)\usercmd.obj \ + $(OUTDIR)\userfunc.obj \ + $(OUTDIR)\vim9class.obj \ + $(OUTDIR)\vim9cmds.obj \ + $(OUTDIR)\vim9compile.obj \ + $(OUTDIR)\vim9execute.obj \ + $(OUTDIR)\vim9expr.obj \ + $(OUTDIR)\vim9instr.obj \ + $(OUTDIR)\vim9script.obj \ + $(OUTDIR)\vim9type.obj \ + $(OUTDIR)\viminfo.obj \ + $(OUTDIR)\winclip.obj \ + $(OUTDIR)\window.obj \ + +!if "$(VIMDLL)" == "yes" +OBJ = $(OBJ) $(OUTDIR)\os_w32dll.obj $(OUTDIR)\vimd.res +EXEOBJC = $(OUTDIR)\os_w32exec.obj $(OUTDIR)\vimc.res +EXEOBJG = $(OUTDIR)\os_w32exeg.obj $(OUTDIR)\vimg.res +CFLAGS = $(CFLAGS) -DVIMDLL +!else +OBJ = $(OBJ) $(OUTDIR)\os_w32exe.obj $(OUTDIR)\vim.res +!endif + +!if "$(OLE)" == "yes" +CFLAGS = $(CFLAGS) -DFEAT_OLE +RCFLAGS = $(RCFLAGS) -DFEAT_OLE +OLE_OBJ = $(OUTDIR)\if_ole.obj +OLE_IDL = if_ole.idl +OLE_LIB = oleaut32.lib +!endif + +!ifndef IME +IME = yes +!endif +!if "$(IME)" == "yes" +CFLAGS = $(CFLAGS) -DFEAT_MBYTE_IME +! ifndef DYNAMIC_IME +DYNAMIC_IME = yes +! endif +! if "$(DYNAMIC_IME)" == "yes" +CFLAGS = $(CFLAGS) -DDYNAMIC_IME +! else +IME_LIB = imm32.lib +! endif +!endif + +!if "$(GUI)" == "yes" +SUBSYSTEM = windows +CFLAGS = $(CFLAGS) -DFEAT_GUI_MSWIN +RCFLAGS = $(RCFLAGS) -DFEAT_GUI_MSWIN +! if "$(VIMDLL)" == "yes" +SUBSYSTEM_CON = console +GVIM = g$(VIM) +CUI_INCL = iscygpty.h +CUI_OBJ = $(OUTDIR)\iscygpty.obj +RCFLAGS = $(RCFLAGS) -DVIMDLL +! else +VIM = g$(VIM) +! endif +GUI_INCL = \ + gui.h +GUI_OBJ = \ + $(OUTDIR)\gui.obj \ + $(OUTDIR)\gui_beval.obj \ + $(OUTDIR)\gui_w32.obj +GUI_LIB = \ + version.lib $(IME_LIB) winspool.lib comctl32.lib +!else +SUBSYSTEM = console +CUI_INCL = iscygpty.h +CUI_OBJ = $(OUTDIR)\iscygpty.obj +!endif +SUBSYSTEM_TOOLS = console + +XDIFF_OBJ = $(OBJDIR)/xdiffi.obj \ + $(OBJDIR)/xemit.obj \ + $(OBJDIR)/xprepare.obj \ + $(OBJDIR)/xutils.obj \ + $(OBJDIR)/xhistogram.obj \ + $(OBJDIR)/xpatience.obj + +XDIFF_DEPS = \ + xdiff/xdiff.h \ + xdiff/xdiffi.h \ + xdiff/xemit.h \ + xdiff/xinclude.h \ + xdiff/xmacros.h \ + xdiff/xprepare.h \ + xdiff/xtypes.h \ + xdiff/xutils.h + + +!if "$(SUBSYSTEM_VER)" != "" +SUBSYSTEM = $(SUBSYSTEM),$(SUBSYSTEM_VER) +SUBSYSTEM_TOOLS = $(SUBSYSTEM_TOOLS),$(SUBSYSTEM_VER) +! if "$(VIMDLL)" == "yes" +SUBSYSTEM_CON = $(SUBSYSTEM_CON),$(SUBSYSTEM_VER) +! endif +# Pass SUBSYSTEM_VER to GvimExt and other tools +MAKEFLAGS_GVIMEXT = $(MAKEFLAGS_GVIMEXT) SUBSYSTEM_VER=$(SUBSYSTEM_VER) +MAKEFLAGS_TOOLS = $(MAKEFLAGS_TOOLS) SUBSYSTEM_VER=$(SUBSYSTEM_VER) +!endif + +!if "$(GUI)" == "yes" && "$(DIRECTX)" == "yes" +CFLAGS = $(CFLAGS) $(DIRECTX_DEFS) +GUI_INCL = $(GUI_INCL) $(DIRECTX_INCL) +GUI_OBJ = $(GUI_OBJ) $(DIRECTX_OBJ) +!endif + +# iconv.dll library (dynamically loaded) +!ifndef ICONV +ICONV = yes +!endif +!if "$(ICONV)" == "yes" +CFLAGS = $(CFLAGS) -DDYNAMIC_ICONV +!endif + +# libintl.dll library +!ifndef GETTEXT +GETTEXT = yes +!endif +!if "$(GETTEXT)" == "yes" +CFLAGS = $(CFLAGS) -DDYNAMIC_GETTEXT +!endif + +# TCL interface +!ifdef TCL +! ifndef TCL_VER +TCL_VER = 86 +TCL_VER_LONG = 8.6 +! endif +! message Tcl requested (version $(TCL_VER)) - root dir is "$(TCL)" +! if "$(DYNAMIC_TCL)" == "yes" +! message Tcl DLL will be loaded dynamically +! ifndef TCL_DLL +TCL_DLL = tcl$(TCL_VER).dll +! endif +CFLAGS = $(CFLAGS) -DFEAT_TCL -DDYNAMIC_TCL -DDYNAMIC_TCL_DLL=\"$(TCL_DLL)\" \ + -DDYNAMIC_TCL_VER=\"$(TCL_VER_LONG)\" +TCL_OBJ = $(OUTDIR)\if_tcl.obj +TCL_INC = /I "$(TCL)\Include" /I "$(TCL)" +TCL_LIB = "$(TCL)\lib\tclstub$(TCL_VER).lib" +! else +CFLAGS = $(CFLAGS) -DFEAT_TCL +TCL_OBJ = $(OUTDIR)\if_tcl.obj +TCL_INC = /I "$(TCL)\Include" /I "$(TCL)" +TCL_LIB = "$(TCL)\lib\tcl$(TCL_VER)vc.lib" +! endif +!endif + +# Lua interface +!ifdef LUA +! ifndef LUA_VER +LUA_VER = 53 +! endif +! message Lua requested (version $(LUA_VER)) - root dir is "$(LUA)" +! if "$(DYNAMIC_LUA)" == "yes" +! message Lua DLL will be loaded dynamically +! endif +CFLAGS = $(CFLAGS) -DFEAT_LUA +LUA_OBJ = $(OUTDIR)\if_lua.obj +LUA_INC = /I "$(LUA)\include" /I "$(LUA)" +! if "$(DYNAMIC_LUA)" == "yes" +CFLAGS = $(CFLAGS) -DDYNAMIC_LUA \ + -DDYNAMIC_LUA_DLL=\"lua$(LUA_VER).dll\" +LUA_LIB = /nodefaultlib:lua$(LUA_VER).lib +! else +LUA_LIB = "$(LUA)\lib\lua$(LUA_VER).lib" +! endif +!endif + +!ifdef PYTHON +! ifdef PYTHON3 +DYNAMIC_PYTHON=yes +DYNAMIC_PYTHON3=yes +! endif +!endif + +# PYTHON interface +!ifdef PYTHON +! ifndef PYTHON_VER +PYTHON_VER = 27 +! endif +! message Python requested (version $(PYTHON_VER)) - root dir is "$(PYTHON)" +! if "$(DYNAMIC_PYTHON)" == "yes" +! message Python DLL will be loaded dynamically +! endif +CFLAGS = $(CFLAGS) -DFEAT_PYTHON +PYTHON_OBJ = $(OUTDIR)\if_python.obj +PYTHON_INC = /I "$(PYTHON)\Include" /I "$(PYTHON)\PC" +! if "$(DYNAMIC_PYTHON)" == "yes" +CFLAGS = $(CFLAGS) -DDYNAMIC_PYTHON \ + -DDYNAMIC_PYTHON_DLL=\"python$(PYTHON_VER).dll\" +PYTHON_LIB = /nodefaultlib:python$(PYTHON_VER).lib +! else +PYTHON_LIB = "$(PYTHON)\libs\python$(PYTHON_VER).lib" +! endif +!endif + +# PYTHON3 interface +!ifdef PYTHON3 +! ifndef PYTHON3_VER +PYTHON3_VER = 36 +! endif +! ifndef DYNAMIC_PYTHON3_DLL +DYNAMIC_PYTHON3_DLL = python$(PYTHON3_VER).dll +! endif +! message Python3 requested (version $(PYTHON3_VER)) - root dir is "$(PYTHON3)" +! if "$(DYNAMIC_PYTHON3)" == "yes" +! message Python3 DLL will be loaded dynamically +! endif +CFLAGS = $(CFLAGS) -DFEAT_PYTHON3 +PYTHON3_OBJ = $(OUTDIR)\if_python3.obj +PYTHON3_INC = /I "$(PYTHON3)\Include" /I "$(PYTHON3)\PC" +! if "$(DYNAMIC_PYTHON3)" == "yes" +CFLAGS = $(CFLAGS) -DDYNAMIC_PYTHON3 \ + -DDYNAMIC_PYTHON3_DLL=\"$(DYNAMIC_PYTHON3_DLL)\" +PYTHON3_LIB = /nodefaultlib:python$(PYTHON3_VER).lib +! else +CFLAGS = $(CFLAGS) -DPYTHON3_DLL=\"$(DYNAMIC_PYTHON3_DLL)\" +PYTHON3_LIB = "$(PYTHON3)\libs\python$(PYTHON3_VER).lib" +! endif +!endif + +# MzScheme interface +!ifdef MZSCHEME +! message MzScheme requested - root dir is "$(MZSCHEME)" +! ifndef MZSCHEME_VER +MZSCHEME_VER = 3m_a0solc +! endif +! ifndef MZSCHEME_COLLECTS +MZSCHEME_COLLECTS=$(MZSCHEME)\collects +! endif +CFLAGS = $(CFLAGS) -DFEAT_MZSCHEME -I "$(MZSCHEME)\include" +! if EXIST("$(MZSCHEME)\lib\msvc\libmzsch$(MZSCHEME_VER).lib") +MZSCHEME_MAIN_LIB=mzsch +! else +MZSCHEME_MAIN_LIB=racket +! endif +! if (EXIST("$(MZSCHEME)\lib\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll") \ + && !EXIST("$(MZSCHEME)\lib\libmzgc$(MZSCHEME_VER).dll")) \ + || (EXIST("$(MZSCHEME)\lib\msvc\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib") \ + && !EXIST("$(MZSCHEME)\lib\msvc\libmzgc$(MZSCHEME_VER).lib")) +! message Building with Precise GC +MZSCHEME_PRECISE_GC = yes +CFLAGS = $(CFLAGS) -DMZ_PRECISE_GC +! endif +! if "$(DYNAMIC_MZSCHEME)" == "yes" +! message MzScheme DLLs will be loaded dynamically +CFLAGS = $(CFLAGS) -DDYNAMIC_MZSCHEME +! if "$(MZSCHEME_PRECISE_GC)" == "yes" +# Precise GC does not use separate dll +CFLAGS = $(CFLAGS) \ + -DDYNAMIC_MZSCH_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\" \ + -DDYNAMIC_MZGC_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\" +! else +CFLAGS = $(CFLAGS) \ + -DDYNAMIC_MZSCH_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\" \ + -DDYNAMIC_MZGC_DLL=\"libmzgc$(MZSCHEME_VER).dll\" +! endif +! else +! if "$(MZSCHEME_DEBUG)" == "yes" +CFLAGS = $(CFLAGS) -DMZSCHEME_FORCE_GC +! endif +! if "$(MZSCHEME_PRECISE_GC)" == "yes" +# Precise GC does not use separate dll +! if EXIST("$(MZSCHEME)\lib\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).def") +# create .lib from .def +MZSCHEME_LIB = lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib +MZSCHEME_EXTRA_DEP = lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib +! else +MZSCHEME_LIB = "$(MZSCHEME)\lib\msvc\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib" +! endif +! else +MZSCHEME_LIB = "$(MZSCHEME)\lib\msvc\libmzgc$(MZSCHEME_VER).lib" \ + "$(MZSCHEME)\lib\msvc\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib" +! endif +! endif +MZSCHEME_OBJ = $(OUTDIR)\if_mzsch.obj +# increase stack size +MZSCHEME_LIB = $(MZSCHEME_LIB) /STACK:8388608 +MZSCHEME_INCL = if_mzsch.h +!endif + +# Perl interface +!ifdef PERL +! ifndef PERL_VER +PERL_VER = 524 +! endif +! message Perl requested (version $(PERL_VER)) - root dir is "$(PERL)" +! if "$(DYNAMIC_PERL)" == "yes" +! message Perl DLL will be loaded dynamically +! endif + +# Is Perl installed in architecture-specific directories? +! if exist($(PERL)\Bin\MSWin32-x86) +PERL_ARCH = \MSWin32-x86 +! endif + +PERL_INCDIR = $(PERL)\Lib$(PERL_ARCH)\Core + +# Version-dependent stuff +PERL_DLL = perl$(PERL_VER).dll +! if exist($(PERL_INCDIR)\perl$(PERL_VER).lib) +PERL_LIB = $(PERL_INCDIR)\perl$(PERL_VER).lib +! else +# For ActivePerl 5.18 and later +PERL_LIB = $(PERL_INCDIR)\libperl$(PERL_VER).a +! endif + +CFLAGS = $(CFLAGS) -DFEAT_PERL -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS + +# Do we want to load Perl dynamically? +! if "$(DYNAMIC_PERL)" == "yes" +CFLAGS = $(CFLAGS) -DDYNAMIC_PERL -DDYNAMIC_PERL_DLL=\"$(PERL_DLL)\" +! undef PERL_LIB +! endif + +PERL_EXE = $(PERL)\Bin$(PERL_ARCH)\perl +PERL_INC = /I $(PERL_INCDIR) +PERL_OBJ = $(OUTDIR)\if_perl.obj $(OUTDIR)\if_perlsfio.obj +XSUBPP = $(PERL)\lib\ExtUtils\xsubpp +! if exist($(XSUBPP)) +XSUBPP = $(PERL_EXE) $(XSUBPP) +! else +XSUBPP = xsubpp +! endif +XSUBPP_TYPEMAP = $(PERL)\lib\ExtUtils\typemap + +!endif + +# +# Support Ruby interface +# +!ifdef RUBY +# Set default value +! ifndef RUBY_VER +RUBY_VER = 22 +! endif +! ifndef RUBY_VER_LONG +RUBY_VER_LONG = 2.2.0 +! endif +! ifndef RUBY_API_VER_LONG +RUBY_API_VER_LONG = $(RUBY_VER_LONG) +! endif +! ifndef RUBY_API_VER +RUBY_API_VER = $(RUBY_API_VER_LONG:.=) +! endif + +! ifndef RUBY_PLATFORM +! if "$(CPU)" == "i386" +RUBY_PLATFORM = i386-mswin32 +! else # CPU +RUBY_PLATFORM = x64-mswin64 +! endif # CPU +RUBY_PLATFORM = $(RUBY_PLATFORM)_$(MSVCRT_VER) +! endif # RUBY_PLATFORM + +! ifndef RUBY_INSTALL_NAME +! ifndef RUBY_MSVCRT_NAME +# Base name of msvcrXX.dll which is used by ruby's dll. +RUBY_MSVCRT_NAME = $(MSVCRT_NAME) +! endif # RUBY_MSVCRT_NAME +! if "$(CPU)" == "i386" +RUBY_INSTALL_NAME = $(RUBY_MSVCRT_NAME)-ruby$(RUBY_API_VER) +! else # CPU +! if EXIST($(RUBY)/lib/ruby/$(RUBY_API_VER_LONG)/x64-mingw-ucrt) +RUBY_INSTALL_NAME = x64-ucrt-ruby$(RUBY_API_VER) +! else +RUBY_INSTALL_NAME = x64-$(RUBY_MSVCRT_NAME)-ruby$(RUBY_API_VER) +! endif +! endif # CPU +! endif # RUBY_INSTALL_NAME + +! message Ruby requested (version $(RUBY_VER)) - root dir is "$(RUBY)" +CFLAGS = $(CFLAGS) -DFEAT_RUBY +RUBY_OBJ = $(OUTDIR)\if_ruby.obj +RUBY_INC = /I "$(RUBY)\include\ruby-$(RUBY_API_VER_LONG)" /I "$(RUBY)\include\ruby-$(RUBY_API_VER_LONG)\$(RUBY_PLATFORM)" +RUBY_LIB = "$(RUBY)\lib\$(RUBY_INSTALL_NAME).lib" +# Do we want to load Ruby dynamically? +! if "$(DYNAMIC_RUBY)" == "yes" +! message Ruby DLL will be loaded dynamically +CFLAGS = $(CFLAGS) -DDYNAMIC_RUBY \ + -DDYNAMIC_RUBY_DLL=\"$(RUBY_INSTALL_NAME).dll\" +! undef RUBY_LIB +! endif +CFLAGS = $(CFLAGS) -DRUBY_VERSION=$(RUBY_VER) +!endif # RUBY + +# +# Support PostScript printing +# +!if "$(POSTSCRIPT)" == "yes" +CFLAGS = $(CFLAGS) -DMSWINPS +!endif # POSTSCRIPT + +# +# FEATURES: TINY, NORMAL, or HUGE +# +CFLAGS = $(CFLAGS) -DFEAT_$(FEATURES) + +# +# MODIFIED_BY - Name of who modified a release version +# +!if "$(MODIFIED_BY)" != "" +CFLAGS = $(CFLAGS) -DMODIFIED_BY=\"$(MODIFIED_BY)\" +!endif + +# +# Always generate the .pdb file, so that we get debug symbols that can be used +# on a crash (doesn't add overhead to the executable). +# Generate edit-and-continue debug info when no optimization - allows to +# debug more conveniently (able to look at variables which are in registers) +# +CFLAGS = $(CFLAGS) /Fd$(OUTDIR)/ $(DEBUGINFO) +!if "$(VIMDLL)" == "yes" +LINK_PDB = /PDB:$(VIMDLLBASE).pdb -debug +!else +LINK_PDB = /PDB:$(VIM).pdb -debug +!endif + +# +# End extra feature include +# +!message + +# CFLAGS with /Fo$(OUTDIR)/ +CFLAGS_OUTDIR=$(CFLAGS) /Fo$(OUTDIR)/ + +PATHDEF_SRC = $(OUTDIR)\pathdef.c + +LINKARGS1 = /nologo +LINKARGS2 = $(CON_LIB) $(GUI_LIB) $(LIBC) $(OLE_LIB) \ + $(LUA_LIB) $(MZSCHEME_LIB) $(PERL_LIB) $(PYTHON_LIB) $(PYTHON3_LIB) $(RUBY_LIB) \ + $(TCL_LIB) $(SOUND_LIB) $(NETBEANS_LIB) $(XPM_LIB) $(SOD_LIB) $(LINK_PDB) + +!ifdef NODEBUG +# Add /opt:ref to remove unreferenced functions and data even when /DEBUG is +# added. +LINKARGS1 = $(LINKARGS1) /opt:ref +!else +LINKARGS1 = $(LINKARGS1) /opt:noref /opt:noicf +!endif + +!if "$(MAP)" == "yes" +# "/map" is for debugging +LINKARGS1 = $(LINKARGS1) /map +!elseif "$(MAP)" == "lines" +# "/mapinfo:lines" is for debugging, only works for VC6 and later +LINKARGS1 = $(LINKARGS1) /map /mapinfo:lines +!endif + +# Enable link time code generation if needed. +!ifdef NODEBUG +! if "$(OPTIMIZE)" != "SPACE" +! if "$(CI)" == "true" || "$(CI)" == "True" +# Enable link time code generation, but do not show the progress. +LINKARGS1 = $(LINKARGS1) /LTCG +! else +# Report link time code generation progress. +LINKARGS1 = $(LINKARGS1) /LTCG:STATUS +! endif +! endif +!endif + +!if "$(CPU)" == "AMD64" && "$(GUI)" == "yes" +# This option is required for VC2012 or later so that 64-bit gvim can +# accept D&D from 32-bit applications. NOTE: This disables 64-bit ASLR, +# therefore the security level becomes as same as VC2010. +LINKARGS1 = $(LINKARGS1) /HIGHENTROPYVA:NO +!endif + +!if "$(VIMDLL)" == "yes" +MAIN_TARGET = $(GVIM).exe $(VIM).exe $(VIMDLLBASE).dll +!else +MAIN_TARGET = $(VIM).exe +!endif + +# Target to run individual tests. +VIMTESTTARGET = $(VIM).exe + +all: $(MAIN_TARGET) \ + vimrun.exe \ + install.exe \ + uninstall.exe \ + xxd/xxd.exe \ + tee/tee.exe \ + GvimExt/gvimext.dll + +# To get around the command line limit: Make use of nmake's response files to +# capture the arguments for $(LINK) in a file using the @<=^^>) +# $LINKARGS2 may contain backslashes, quotes and chevrons, escape them all. +E0_LINKARGS2 = $(LINKARGS2:\=\\) +E00_LINKARGS2 = $(E0_LINKARGS2:"=\") +# ") stop the string +E000_LINKARGS2 = $(E00_LINKARGS2:<=^^<) +E_LINKARGS2 = $(E000_LINKARGS2:>=^^>) + +$(PATHDEF_SRC): Make_mvc.mak + @echo creating $(PATHDEF_SRC) + @echo /* pathdef.c */ > $(PATHDEF_SRC) + @echo #include "vim.h" >> $(PATHDEF_SRC) + @echo char_u *default_vim_dir = (char_u *)"$(VIMRCLOC:\=\\)"; >> $(PATHDEF_SRC) + @echo char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR:\=\\)"; >> $(PATHDEF_SRC) + @echo char_u *all_cflags = (char_u *)"$(CC:\=\\) $(E_CFLAGS)"; >> $(PATHDEF_SRC) + @echo char_u *all_lflags = (char_u *)"$(LINK:\=\\) $(LINKARGS1:\=\\) $(E_LINKARGS2)"; >> $(PATHDEF_SRC) + @echo char_u *compiled_user = (char_u *)"$(USERNAME)"; >> $(PATHDEF_SRC) + @echo char_u *compiled_sys = (char_u *)"$(USERDOMAIN)"; >> $(PATHDEF_SRC) + +# End Custom Build +proto.h: \ + proto/alloc.pro \ + proto/arabic.pro \ + proto/arglist.pro \ + proto/autocmd.pro \ + proto/blob.pro \ + proto/blowfish.pro \ + proto/buffer.pro \ + proto/bufwrite.pro \ + proto/change.pro \ + proto/charset.pro \ + proto/cindent.pro \ + proto/clientserver.pro \ + proto/clipboard.pro \ + proto/cmdexpand.pro \ + proto/cmdhist.pro \ + proto/crypt.pro \ + proto/crypt_zip.pro \ + proto/debugger.pro \ + proto/dict.pro \ + proto/diff.pro \ + proto/digraph.pro \ + proto/drawline.pro \ + proto/drawscreen.pro \ + proto/edit.pro \ + proto/eval.pro \ + proto/evalbuffer.pro \ + proto/evalfunc.pro \ + proto/evalvars.pro \ + proto/evalwindow.pro \ + proto/ex_cmds.pro \ + proto/ex_cmds2.pro \ + proto/ex_docmd.pro \ + proto/ex_eval.pro \ + proto/ex_getln.pro \ + proto/fileio.pro \ + proto/filepath.pro \ + proto/findfile.pro \ + proto/float.pro \ + proto/getchar.pro \ + proto/gui_xim.pro \ + proto/hardcopy.pro \ + proto/hashtab.pro \ + proto/help.pro \ + proto/highlight.pro \ + proto/indent.pro \ + proto/insexpand.pro \ + proto/json.pro \ + proto/list.pro \ + proto/locale.pro \ + proto/logfile.pro \ + proto/main.pro \ + proto/map.pro \ + proto/mark.pro \ + proto/match.pro \ + proto/memfile.pro \ + proto/memline.pro \ + proto/menu.pro \ + proto/message.pro \ + proto/misc1.pro \ + proto/misc2.pro \ + proto/mouse.pro \ + proto/move.pro \ + proto/mbyte.pro \ + proto/normal.pro \ + proto/ops.pro \ + proto/option.pro \ + proto/optionstr.pro \ + proto/os_mswin.pro \ + proto/winclip.pro \ + proto/os_win32.pro \ + proto/popupmenu.pro \ + proto/popupwin.pro \ + proto/profiler.pro \ + proto/quickfix.pro \ + proto/regexp.pro \ + proto/register.pro \ + proto/scriptfile.pro \ + proto/screen.pro \ + proto/search.pro \ + proto/session.pro \ + proto/sha256.pro \ + proto/sign.pro \ + proto/spell.pro \ + proto/spellfile.pro \ + proto/spellsuggest.pro \ + proto/strings.pro \ + proto/syntax.pro \ + proto/tag.pro \ + proto/term.pro \ + proto/testing.pro \ + proto/textformat.pro \ + proto/textobject.pro \ + proto/textprop.pro \ + proto/time.pro \ + proto/typval.pro \ + proto/ui.pro \ + proto/undo.pro \ + proto/usercmd.pro \ + proto/userfunc.pro \ + proto/vim9class.pro \ + proto/vim9cmds.pro \ + proto/vim9compile.pro \ + proto/vim9execute.pro \ + proto/vim9expr.pro \ + proto/vim9instr.pro \ + proto/vim9script.pro \ + proto/vim9type.pro \ + proto/viminfo.pro \ + proto/window.pro \ + $(SOUND_PRO) \ + $(NETBEANS_PRO) \ + $(CHANNEL_PRO) + +.SUFFIXES: .cod .i + +# Generate foo.cod (mixed source and assembly listing) from foo.c via "nmake +# foo.cod" +.c.cod: + $(CC) $(CFLAGS) /FAcs $< + +# Generate foo.i (preprocessor listing) from foo.c via "nmake foo.i" +.c.i: + $(CC) $(CFLAGS) /P /C $< + +# vim: set noet sw=8 ts=8 sts=0 wm=0 tw=0: diff --git a/src/Make_vms.mms b/src/Make_vms.mms new file mode 100644 index 0000000..8dd5454 --- /dev/null +++ b/src/Make_vms.mms @@ -0,0 +1,1260 @@ +# +# Makefile for Vim on OpenVMS +# +# Maintainer: Zoltan Arpadffy +# Last change: 2021 Dec 20 +# +# This script has been tested on VMS 6.2 to 8.4 on DEC Alpha, VAX and IA64 +# with MMS and MMK +# +# The following could be built: +# vim.exe: standard (terminal, GUI/Motif, GUI/GTK) +# dvim.exe: debug +# +# Edit the lines in the Configuration section below for fine tuning. +# +# To build: mms/descrip=Make_vms.mms /ignore=warning +# To clean up: mms/descrip=Make_vms.mms clean +# +# Hints and detailed description could be found in INSTALLVMS.TXT file. +# +###################################################################### +# Configuration section. +###################################################################### + +# Compiler selection. +# Comment out if you use the VAXC compiler +DECC = YES + +# Build model selection +# TINY - No optional features enabled +# NORMAL - A default selection of features enabled +# HUGE - All possible features enabled. +# Please select one of these alternatives above. +MODEL = HUGE + +# GUI or terminal mode executable. +# Comment out if you want just the character terminal mode only. +# GUI with Motif +# GUI = YES + +# GUI with GTK +# If you have GTK installed you might want to enable this option. +# NOTE: you will need to properly define GTK_DIR below +# NOTE: since Vim 7.3 GTK 2+ is used that is not ported to VMS, +# therefore this option should not be used +# GTK = YES + +# GUI/Motif with XPM +# If you have XPM installed you might want to build Motif version with toolbar +# XPM = YES + +# Comment out if you want the compiler version with :ver command. +# NOTE: This part can make some complications if you're using some +# predefined symbols/flags for your compiler. If does, just leave behind +# the comment variable CCVER. +CCVER = YES + +# Uncomment if want a debug version. Resulting executable is DVIM.EXE +# Development purpose only! Normally, it should not be defined. !!! +# DEBUG = YES + +# Languages support for Perl, Python, TCL etc. +# If you don't need it really, leave them behind the comment. +# You will need related libraries, include files etc. +# VIM_TCL = YES +# VIM_PERL = YES +# VIM_PYTHON = YES +# VIM_RUBY = YES +# VIM_LUA = YES + +# X Input Method. For entering special languages like chinese and +# Japanese. +# If you don't need it really, leave it behind the comment. +# VIM_XIM = YES + +# Allow any white space to separate the fields in a tags file +# When not defined, only a TAB is allowed. +# VIM_TAG_ANYWHITE = YES + +# Allow FEATURE_MZSCHEME +# VIM_MZSCHEME = YES + +# Use ICONV +# VIM_ICONV = YES + +###################################################################### +# Directory, library and include files configuration section. +# Normally you need not to change anything below. ! +# These may need to be defined if things are not in standard locations +# +# You can find some explanation in INSTALLVMS.TXT +###################################################################### + +# Compiler setup + +.IFDEF MMSVAX +.IFDEF DECC # VAX with DECC +CC_DEF = cc # /decc # some versions require /decc switch but when it is not required /ver might fail +PREFIX = /prefix=all/name=(upper,short) +OPTIMIZE= /noopt # do not optimize on VAX. The compiler has hard time with crypto functions +.ELSE # VAX with VAXC +CC_DEF = cc +PREFIX = +OPTIMIZE= /noopt +CCVER = +.ENDIF +.ELSE # AXP and IA64 with DECC +CC_DEF = cc +PREFIX = /prefix=all/name=(upper,short) +OPTIMIZE= /opt +.ENDIF + + +LD_DEF = link +C_INC = [.proto] + +.IFDEF DEBUG +DEBUG_DEF = ,"DEBUG" +TARGET = dvim.exe +CFLAGS = /debug/noopt$(PREFIX) +LDFLAGS = /debug +.ELSE +TARGET = vim.exe +CFLAGS = $(OPTIMIZE)$(PREFIX) +LDFLAGS = +.ENDIF + +# Predefined VIM directories +# Please, use $VIM and $VIMRUNTIME logicals instead +VIMLOC = "" +VIMRUN = "" + +CONFIG_H = os_vms_conf.h + +# GTK or XPM but not both +.IFDEF GTK +.IFDEF GUI +.ELSE +GUI = YES +.ENDIF +.IFDEF XPM +XPM = "" +.ENDIF +.ENDIF + +.IFDEF XPM +.IFDEF GUI +.ELSE +GUI = YES +.ENDIF +.IFDEF GTK +GTK = "" +.ENDIF +.ENDIF + +.IFDEF GUI +# X/Motif/GTK executable (also works in terminal mode ) + +.IFDEF GTK +# NOTE: you need to set up your GTK_DIR (GTK root directory), because it is +# unique on every system - logicals are not accepted +# please note: directory should end with . in order to /trans=conc work +# This value for GTK_DIR is an example. +GTK_DIR = DKA0:[WORK.GTK1210.] +DEFS = "HAVE_CONFIG_H","FEAT_GUI_GTK" +LIBS = ,OS_VMS_GTK.OPT/OPT +GUI_FLAG = /float=ieee/ieee=denorm +GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_gtk_x11.c gui_beval.c pty.c +GUI_OBJ = gui.obj gui_gtk.obj gui_gtk_f.obj gui_gtk_x11.obj gui_beval.obj pty.obj +GUI_INC = ,"/gtk_root/gtk","/gtk_root/glib" +# GUI_INC_VER is used just for :ver information +# this string should escape from C and DCL in the same time +GUI_INC_VER= ,\""/gtk_root/gtk\"",\""/gtk_root/glib\"" +.ELSE +MOTIF = YES +.IFDEF XPM +DEFS = "HAVE_CONFIG_H","FEAT_GUI_MOTIF","HAVE_XPM" +XPM_INC = ,[.xpm.include] +XPM_LIB = ,OS_VMS_XPM.OPT/OPT +.ELSE +DEFS = "HAVE_CONFIG_H","FEAT_GUI_MOTIF" +XPM_INC = +.ENDIF +LIBS = ,OS_VMS_MOTIF.OPT/OPT +GUI_FLAG = +GUI_SRC = gui.c gui_motif.c gui_x11.c gui_beval.c gui_xmdlg.c gui_xmebw.c +GUI_OBJ = gui.obj gui_motif.obj gui_x11.obj gui_beval.obj gui_xmdlg.obj gui_xmebw.obj +GUI_INC = +.ENDIF + +# You need to define these variables if you do not have DECW files +# at standard location +GUI_INC_DIR = ,decw$include: +# GUI_LIB_DIR = ,sys$library: + +.ELSE +# Character terminal only executable +DEFS = "HAVE_CONFIG_H" +LIBS = +.ENDIF + +.IFDEF VIM_PERL +# Perl related setup. +PERL = perl +PERL_DEF = ,"FEAT_PERL" +PERL_SRC = if_perlsfio.c if_perl.xs +PERL_OBJ = if_perlsfio.obj if_perl.obj +PERL_LIB = ,OS_VMS_PERL.OPT/OPT +PERL_INC = ,dka0:[perlbuild.perl.lib.vms_axp.5_6_1.core] +.ENDIF + +.IFDEF VIM_PYTHON +# Python related setup. +PYTHON_DEF = ,"FEAT_PYTHON" +PYTHON_SRC = if_python.c +PYTHON_OBJ = if_python.obj +PYTHON_LIB = ,OS_VMS_PYTHON.OPT/OPT +PYTHON_INC = ,PYTHON_INCLUDE +.ENDIF + +.IFDEF VIM_TCL +# TCL related setup. +TCL_DEF = ,"FEAT_TCL" +TCL_SRC = if_tcl.c +TCL_OBJ = if_tcl.obj +TCL_LIB = ,OS_VMS_TCL.OPT/OPT +TCL_INC = ,dka0:[tcl80.generic] +.ENDIF + +.IFDEF VIM_RUBY +# RUBY related setup. +RUBY_DEF = ,"FEAT_RUBY" +RUBY_SRC = if_ruby.c +RUBY_OBJ = if_ruby.obj +RUBY_LIB = ,OS_VMS_RUBY.OPT/OPT +RUBY_INC = +.ENDIF + +.IFDEF VIM_LUA +# LUA related setup. +LUA_DEF = ,"FEAT_LUA" +LUA_SRC = if_lua.c +LUA_OBJ = if_lua.obj +LUA_LIB = ,OS_VMS_LUA.OPT/OPT +LUA_INC = ,LUA$ROOT:[INCLUDE] +.ENDIF + +.IFDEF VIM_XIM +# XIM related setup. +.IFDEF GUI +XIM_DEF = ,"FEAT_XIM" +.ENDIF +.ENDIF + +.IFDEF VIM_MZSCHEME +# MZSCHEME related setup +MZSCH_DEF = ,"FEAT_MZSCHEME" +MZSCH_SRC = if_mzsch.c +MZSCH_OBJ = if_mzsch.obj +.ENDIF + +.IFDEF VIM_ICONV +# ICONV related setup +ICONV_DEF = ,"USE_ICONV" +.ENDIF + +# XDIFF related setup. +XDIFF_SRC = xdiffi.c,xemit.c,xprepare.c,xutils.c,xhistogram.c,xpatience.c +XDIFF_OBJ = xdiffi.obj,xemit.obj,xprepare.obj,xutils.obj,xhistogram.obj,xpatience.obj +XDIFF_INC = ,[.xdiff] + +###################################################################### +# End of configuration section. +# Please, do not change anything below without programming experience. +###################################################################### + +MODEL_DEF = "FEAT_$(MODEL)", + +# These go into pathdef.c +VIMUSER = "''F$EDIT(F$GETJPI(" ","USERNAME"),"TRIM")'" +VIMHOST = "''F$TRNLNM("SYS$NODE")'''F$TRNLNM("UCX$INET_HOST")'.''F$TRNLNM("UCX$INET_DOMAIN")'" + +.SUFFIXES : .obj .c + +ALL_CFLAGS = /def=($(MODEL_DEF)$(DEFS)$(DEBUG_DEF)$(PERL_DEF)$(PYTHON_DEF) - + $(TCL_DEF)$(RUBY_DEF)$(LUA_DEF)$(XIM_DEF)$(TAG_DEF)$(MZSCH_DEF) - + $(ICONV_DEF)) - + $(CFLAGS)$(GUI_FLAG) - + /include=($(C_INC)$(GUI_INC_DIR)$(GUI_INC)$(PERL_INC)$(PYTHON_INC) - + $(TCL_INC)$(XDIFF_INC)$(XPM_INC)) + +# CFLAGS displayed in :ver information +# It is specially formatted for correct display of unix like includes +# as $(GUI_INC) - replaced with $(GUI_INC_VER) +# Otherwise should not be any other difference. +ALL_CFLAGS_VER = /def=($(MODEL_DEF)$(DEFS)$(DEBUG_DEF)$(PERL_DEF)$(PYTHON_DEF) - + $(TCL_DEF)$(RUBY_DEF)$(LUA_DEF)$(XIM_DEF)$(TAG_DEF)$(MZSCH_DEF) - + $(ICONV_DEF)) - + $(CFLAGS)$(GUI_FLAG) - + /include=($(C_INC)$(GUI_INC_DIR)$(GUI_INC_VER)$(PERL_INC)$(PYTHON_INC) - + $(TCL_INC)$(XDIFF_INC)$(XPM_INC)) + +ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) $(XPM_LIB)\ + $(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB) $(LUA_LIB) + +SRC = \ + alloc.c \ + arabic.c \ + arglist.c \ + autocmd.c \ + beval.c \ + blob.c \ + blowfish.c \ + buffer.c \ + bufwrite.c \ + change.c \ + charset.c \ + cindent.c \ + clientserver.c \ + clipboard.c \ + cmdexpand.c \ + cmdhist.c \ + crypt.c \ + crypt_zip.c \ + debugger.c \ + dict.c \ + diff.c \ + digraph.c \ + drawline.c \ + drawscreen.c \ + edit.c \ + eval.c \ + evalbuffer.c \ + evalfunc.c \ + evalvars.c \ + evalwindow.c \ + ex_cmds.c \ + ex_cmds2.c \ + ex_docmd.c \ + ex_eval.c \ + ex_getln.c \ + fileio.c \ + filepath.c, \ + findfile.c \ + float.c \ + fold.c \ + getchar.c \ + gui_xim.c \ + hardcopy.c \ + hashtab.c \ + help.c \ + highlight.c \ + if_cscope.c \ + if_xcmdsrv.c \ + indent.c \ + insexpand.c \ + json.c \ + list.c \ + locale.c \ + logfile.c \ + main.c \ + map.c \ + mark.c \ + match.c \ + mbyte.c \ + memfile.c \ + memline.c \ + menu.c \ + message.c \ + misc1.c \ + misc2.c \ + mouse.c \ + move.c \ + normal.c \ + ops.c \ + option.c \ + optionstr.c \ + os_unix.c \ + os_vms.c \ + pathdef.c \ + popupmenu.c \ + popupwin.c \ + profiler.c \ + quickfix.c \ + regexp.c \ + register.c \ + screen.c \ + scriptfile.c \ + search.c \ + session.c \ + sha256.c \ + sign.c \ + spell.c \ + spellfile.c \ + spellsuggest.c \ + strings.c \ + syntax.c \ + tag.c \ + term.c \ + termlib.c \ + testing.c \ + textformat.c \ + textobject.c \ + textprop.c \ + time.c \ + typval.c \ + ui.c \ + undo.c \ + usercmd.c \ + userfunc.c \ + version.c \ + vim9class.c \ + vim9cmds.c \ + vim9compile.c \ + vim9execute.c \ + vim9expr.c \ + vim9instr.c \ + vim9script.c \ + vim9type.c \ + viminfo.c \ + window.c \ + $(GUI_SRC) \ + $(PERL_SRC) \ + $(PYTHON_SRC) \ + $(TCL_SRC) \ + $(RUBY_SRC) \ + $(LUA_SRC) \ + $(MZSCH_SRC) \ + $(XDIFF_SRC) + +OBJ = \ + alloc.obj \ + arabic.obj \ + arglist.obj \ + autocmd.obj \ + beval.obj \ + blob.obj \ + blowfish.obj \ + buffer.obj \ + bufwrite.obj \ + change.obj \ + charset.obj \ + cindent.obj \ + clientserver.obj \ + clipboard.obj \ + cmdexpand.obj \ + cmdhist.obj \ + crypt.obj \ + crypt_zip.obj \ + debugger.obj \ + dict.obj \ + diff.obj \ + digraph.obj \ + drawline.obj \ + drawscreen.obj \ + edit.obj \ + eval.obj \ + evalbuffer.obj \ + evalfunc.obj \ + evalvars.obj \ + evalwindow.obj \ + ex_cmds.obj \ + ex_cmds2.obj \ + ex_docmd.obj \ + ex_eval.obj \ + ex_getln.obj \ + fileio.obj \ + filepath.obj \ + findfile.obj \ + float.obj \ + fold.obj \ + getchar.obj \ + gui_xim.obj \ + hardcopy.obj \ + hashtab.obj \ + help.obj \ + highlight.obj \ + if_cscope.obj \ + if_mzsch.obj \ + if_xcmdsrv.obj \ + indent.obj \ + insexpand.obj \ + json.obj \ + list.obj \ + locale.obj \ + logfile.obj \ + main.obj \ + map.obj \ + mark.obj \ + match.obj \ + mbyte.obj \ + memfile.obj \ + memline.obj \ + menu.obj \ + message.obj \ + misc1.obj \ + misc2.obj \ + mouse.obj \ + move.obj \ + normal.obj \ + ops.obj \ + option.obj \ + optionstr.obj \ + os_unix.obj \ + os_vms.obj \ + pathdef.obj \ + popupmenu.obj \ + popupwin.obj \ + profiler.obj \ + quickfix.obj \ + regexp.obj \ + register.obj \ + screen.obj \ + scriptfile.obj \ + search.obj \ + session.obj \ + sha256.obj \ + sign.obj \ + spell.obj \ + spellfile.obj \ + spellsuggest.obj \ + strings.obj \ + syntax.obj \ + tag.obj \ + term.obj \ + termlib.obj \ + testing.obj \ + textformat.obj \ + textobject.obj \ + textprop.obj \ + time.obj \ + typval.obj \ + ui.obj \ + undo.obj \ + usercmd.obj \ + userfunc.obj \ + version.obj \ + vim9class.obj \ + vim9cmds.obj \ + vim9compile.obj \ + vim9execute.obj \ + vim9expr.obj \ + vim9instr.obj \ + vim9script.obj \ + vim9type.obj \ + viminfo.obj \ + window.obj \ + $(GUI_OBJ) \ + $(PERL_OBJ) \ + $(PYTHON_OBJ) \ + $(TCL_OBJ) \ + $(RUBY_OBJ) \ + $(LUA_OBJ) \ + $(MZSCH_OBJ) \ + $(XDIFF_OBJ) + +# Default target is making the executable +all : [.auto]config.h mmk_compat motif_env gtk_env perl_env python_env tcl_env ruby_env lua_env $(TARGET) + ! $@ + +[.auto]config.h : $(CONFIG_H) + copy/nolog $(CONFIG_H) [.auto]config.h + +mmk_compat : + -@ open/write pd pathdef.c + -@ write pd "/* Empty file to satisfy MMK depend. */" + -@ write pd "/* It will be overwritten later on... */" + -@ close pd +clean : + -@ if "''F$SEARCH("*.exe")'" .NES. "" then delete/noconfirm/nolog *.exe;* + -@ if "''F$SEARCH("*.obj")'" .NES. "" then delete/noconfirm/nolog *.obj;* + -@ if "''F$SEARCH("[.auto]config.h")'" .NES. "" then delete/noconfirm/nolog [.auto]config.h;* + -@ if "''F$SEARCH("pathdef.c")'" .NES. "" then delete/noconfirm/nolog pathdef.c;* + -@ if "''F$SEARCH("if_perl.c")'" .NES. "" then delete/noconfirm/nolog if_perl.c;* + -@ if "''F$SEARCH("*.opt")'" .NES. "" then delete/noconfirm/nolog *.opt;* + -@ if "''F$SEARCH("*.dmp")'" .NES. "" then delete/noconfirm/nolog *.dmp;* + +# Link the target +$(TARGET) : $(OBJ) +# make an OPT file - as the obj file list is too long for one command line + -@ DIRECTORY *.OBJ. /BRIEF/COLUMNS=1/NOHEADING/NOTRAILING /SELECT=FILE=(NONODE,NODEVICE,NODIRECTORY,NOVERSION)/OUTPUT=ALL_OBJS_LIST.OPT + $(LD_DEF) $(LDFLAGS) /exe=$(TARGET) ALL_OBJS_LIST.OPT/OPT $(ALL_LIBS) + +.c.obj : + $(CC_DEF) $(ALL_CFLAGS) $< + +pathdef.c : check_ccver $(CONFIG_H) + -@ write sys$output "creating PATHDEF.C file." + -@ open/write pd pathdef.c + -@ write pd "/* pathdef.c -- DO NOT EDIT! */" + -@ write pd "/* This file is automatically created by MAKE_VMS.MMS" + -@ write pd " * Change the file MAKE_VMS.MMS Only. */" + -@ write pd "typedef unsigned char char_u;" + -@ write pd "char_u *default_vim_dir = (char_u *)"$(VIMLOC)";" + -@ write pd "char_u *default_vimruntime_dir = (char_u *)"$(VIMRUN)";" + -@ write pd "char_u *all_cflags = (char_u *)""$(CC_DEF)$(ALL_CFLAGS_VER)"";" + -@ write pd "char_u *all_lflags = (char_u *)""$(LD_DEF)$(LDFLAGS) /exe=$(TARGET) ALL_OBJS_LIST.OPT/OPT $(ALL_LIBS)"";" + -@ write pd "char_u *compiler_version = (char_u *) ""''CC_VER'"";" + -@ write pd "char_u *compiled_user = (char_u *) "$(VIMUSER)";" + -@ write pd "char_u *compiled_sys = (char_u *) "$(VIMHOST)";" + -@ write pd "char_u *compiled_arch = (char_u *) ""$(MMSARCH_NAME)"";" + -@ close pd + +if_perl.c : if_perl.xs + -@ $(PERL) PERL_ROOT:[LIB.ExtUtils]xsubpp -prototypes -typemap - PERL_ROOT:[LIB.ExtUtils]typemap if_perl.xs >> $@ + +make_vms.mms : + -@ write sys$output "The name of the makefile MUST be !!!" + +.IFDEF CCVER +# This part can make some complications if you're using some predefined +# symbols/flags for your compiler. If does, just comment out CCVER variable +check_ccver : + -@ define sys$output cc_ver.tmp + -@ $(CC_DEF)/version + -@ deassign sys$output + -@ open/read file cc_ver.tmp + -@ read file CC_VER + -@ close file + -@ delete/noconfirm/nolog cc_ver.tmp.* +.ELSE +check_ccver : + -@ ! +.ENDIF + +.IFDEF MOTIF +motif_env : +.IFDEF XPM + -@ write sys$output "using DECW/Motif/XPM environment." + -@ write sys$output "creating OS_VMS_XPM.OPT file." + -@ open/write opt_file OS_VMS_XPM.OPT +.IFDEF MMSVAX + -@ write opt_file "[.xpm.vms.vax]libxpm.olb/lib" +.ENDIF +.IFDEF MMSALPHA + -@ write opt_file "[.xpm.vms.axp]libxpm.olb/lib" +.ENDIF +.IFDEF MMSIA64 + -@ write opt_file "[.xpm.vms.ia64]libxpm.olb/lib" +.ENDIF + -@ close opt_file +.ELSE + -@ write sys$output "using DECW/Motif environment." +.ENDIF + -@ write sys$output "creating OS_VMS_MOTIF.OPT file." + -@ open/write opt_file OS_VMS_MOTIF.OPT + -@ write opt_file "sys$share:decw$xmlibshr12.exe/share,-" + -@ write opt_file "sys$share:decw$xtlibshrr5.exe/share,-" + -@ write opt_file "sys$share:decw$xlibshr.exe/share" + -@ close opt_file +.ELSE +motif_env : + -@ ! +.ENDIF + + +.IFDEF GTK +gtk_env : + -@ write sys$output "using GTK environment:" + -@ define/nolog gtk_root /trans=conc $(GTK_DIR) + -@ show logical gtk_root + -@ write sys$output " include path: "$(GUI_INC)"" + -@ write sys$output "creating OS_VMS_GTK.OPT file." + -@ open/write opt_file OS_VMS_GTK.OPT + -@ write opt_file "gtk_root:[glib]libglib.exe /share,-" + -@ write opt_file "gtk_root:[glib.gmodule]libgmodule.exe /share,-" + -@ write opt_file "gtk_root:[gtk.gdk]libgdk.exe /share,-" + -@ write opt_file "gtk_root:[gtk.gtk]libgtk.exe /share,-" + -@ write opt_file "sys$share:decw$xmlibshr12.exe/share,-" + -@ write opt_file "sys$share:decw$xtlibshrr5.exe/share,-" + -@ write opt_file "sys$share:decw$xlibshr.exe/share" + -@ close opt_file +.ELSE +gtk_env : + -@ ! +.ENDIF + +.IFDEF VIM_PERL +perl_env : + -@ write sys$output "using PERL environment:" + -@ show logical PERLSHR + -@ write sys$output " include path: ""$(PERL_INC)""" + -@ show symbol perl + -@ open/write pd if_perl.c + -@ write pd "/* Empty file to satisfy MMK depend. */" + -@ write pd "/* It will be overwritten later on... */" + -@ close pd + -@ write sys$output "creating OS_VMS_PERL.OPT file." + -@ open/write opt_file OS_VMS_PERL.OPT + -@ write opt_file "PERLSHR /share" + -@ close opt_file +.ELSE +perl_env : + -@ ! +.ENDIF + +.IFDEF VIM_PYTHON +python_env : + -@ write sys$output "using PYTHON environment:" + -@ show logical PYTHON_INCLUDE + -@ show logical PYTHON_OLB + -@ write sys$output "creating OS_VMS_PYTHON.OPT file." + -@ open/write opt_file OS_VMS_PYTHON.OPT + -@ write opt_file "PYTHON_OLB:PYTHON.OLB /share" + -@ close opt_file +.ELSE +python_env : + -@ ! +.ENDIF + +.IFDEF VIM_TCL +tcl_env : + -@ write sys$output "using TCL environment:" + -@ show logical TCLSHR + -@ write sys$output " include path: ""$(TCL_INC)""" + -@ write sys$output "creating OS_VMS_TCL.OPT file." + -@ open/write opt_file OS_VMS_TCL.OPT + -@ write opt_file "TCLSHR /share" + -@ close opt_file +.ELSE +tcl_env : + -@ ! +.ENDIF + +.IFDEF VIM_RUBY +ruby_env : + -@ write sys$output "using RUBY environment:" + -@ write sys$output " include path: ""$(RUBY_INC)""" + -@ write sys$output "creating OS_VMS_RUBY.OPT file." + -@ open/write opt_file OS_VMS_RUBY.OPT + -@ write opt_file "RUBYSHR /share" + -@ close opt_file +.ELSE +ruby_env : + -@ ! +.ENDIF + +.IFDEF VIM_LUA +lua_env : + -@ write sys$output "using LUA environment:" + -@ write sys$output " include path: ""$(LUA_INC)""" + -@ write sys$output "creating OS_VMS_LUA.OPT file." + -@ open/write opt_file OS_VMS_LUA.OPT + -@ write opt_file "LUA$ROOT:[LIB]LUA$SHR.EXE /share" + -@ close opt_file +.ELSE +lua_env : + -@ ! +.ENDIF + +alloc.obj : alloc.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +arabic.obj : arabic.c vim.h +arglist.obj : arglist.c vim.h [.auto]config.h feature.h os_unix.h +autocmd.obj : autocmd.c vim.h [.auto]config.h feature.h os_unix.h +blowfish.obj : blowfish.c vim.h [.auto]config.h feature.h os_unix.h +blob.obj : blob.c vim.h [.auto]config.h feature.h os_unix.h +buffer.obj : buffer.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +bufwrite.obj : bufwrite.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +change.obj : change.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +charset.obj : charset.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +cindent.obj : cindent.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +clientserver.obj : clientserver.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +clipboard.obj : clipboard.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +cmdexpand.obj : cmdexpand.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +cmdhist.obj : cmdhist.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +crypt.obj : crypt.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h regexp.h gui.h \ + beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \ + errors.h globals.h +crypt_zip.obj : crypt_zip.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h +debugger.obj : debugger.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +dict.obj : dict.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h regexp.h gui.h \ + beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \ + errors.h globals.h +diff.obj : diff.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +digraph.obj : digraph.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +drawline.obj : drawline.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +drawscreen.obj : drawscreen.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +edit.obj : edit.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +eval.obj : eval.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +evalbuffer.obj : evalbuffer.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h +evalfunc.obj : evalfunc.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h version.h +evalvars.obj : evalvars.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h version.h +evalwindow.obj : evalwindow.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h +ex_cmds.obj : ex_cmds.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +ex_cmds2.obj : ex_cmds2.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +ex_docmd.obj : ex_docmd.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h ex_cmdidxs.h +ex_eval.obj : ex_eval.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +ex_getln.obj : ex_getln.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +fileio.obj : fileio.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +filepath.obj : filepath.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +findfile.obj : findfile.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +float.obj : float.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +fold.obj : fold.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +getchar.obj : getchar.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +gui_xim.obj : gui_xim.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +hardcopy.obj : hardcopy.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +hashtab.obj : hashtab.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +help.obj : help.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +highlight.obj : highlight.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +if_cscope.obj : if_cscope.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +if_xcmdsrv.obj : if_xcmdsrv.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +if_mzsch.obj : if_mzsch.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro ex_cmds.h proto.h \ + errors.h globals.h if_mzsch.h +indent.obj : indent.c vim.h [.auto]config.h feature.h os_unix.h +insexpand.obj : insexpand.c vim.h [.auto]config.h feature.h os_unix.h +json.obj : json.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +list.obj : list.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h regexp.h gui.h \ + beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \ + errors.h globals.h +locale.obj : locale.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h regexp.h gui.h \ + beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \ + errors.h globals.h +logfile.obj : logfile.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h regexp.h gui.h \ + beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \ + errors.h globals.h +main.obj : main.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h \ + arabic.c +map.obj : map.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +mark.obj : mark.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +match.obj : match.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +memfile.obj : memfile.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +memline.obj : memline.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +menu.obj : menu.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +message.obj : message.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +misc1.obj : misc1.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h \ + version.h +misc2.obj : misc2.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +mouse.obj : mouse.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +move.obj : move.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +mbyte.obj : mbyte.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +normal.obj : normal.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h nv_cmdidxs.h nv_cmds.h +ops.obj : ops.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +option.obj : option.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h optiondefs.h +optionstr.obj : optionstr.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +os_unix.obj : os_unix.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h os_unixx.h +os_vms.obj : os_vms.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h os_unixx.h +pathdef.obj : pathdef.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +popupmenu.obj : popupmenu.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +popupwin.obj : popupwin.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +profiler.obj : profiler.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +quickfix.obj : quickfix.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +regexp.obj : regexp.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +register.obj : register.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +scriptfile.obj : scriptfile.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +screen.obj : screen.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +search.obj : search.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +session.obj : session.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +sha256.obj : sha256.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h regexp.h gui.h \ + beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \ + errors.h globals.h +sign.obj : sign.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h regexp.h gui.h \ + beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \ + errors.h globals.h +spell.obj : spell.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +spellfile.obj : spellfile.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h +spellsuggest.obj : spellsuggest.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h +strings.obj : strings.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h +syntax.obj : syntax.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +tag.obj : tag.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +term.obj : term.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +termlib.obj : termlib.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +testing.obj : testing.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +textformat.obj : textformat.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +textobject.obj : textobject.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +textprop.obj : textprop.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +time.obj : time.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +typval.obj : typval.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +ui.obj : ui.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +undo.obj : undo.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +usercmd.obj : usercmd.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h +userfunc.obj : userfunc.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ + proto.h errors.h globals.h +version.obj : version.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +viminfo.obj : viminfo.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +vim9class.obj : vim9class.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +vim9cmds.obj : vim9cmds.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +vim9compile.obj : vim9compile.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +vim9execute.obj : vim9execute.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +vim9expr.obj : vim9expr.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +vim9instr.obj : vim9instr.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +vim9script.obj : vim9script.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +vim9type.obj : vim9type.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +window.obj : window.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +gui.obj : gui.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +gui_gtk.obj : gui_gtk.c gui_gtk_f.h vim.h [.auto]config.h feature.h \ + os_unix.h ascii.h keymap.h termdefs.h macros.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h \ + proto.h errors.h globals.h [-.pixmaps]stock_icons.h +gui_gtk_f.obj : gui_gtk_f.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h gui_gtk_f.h +gui_motif.obj : gui_motif.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h [-.pixmaps]alert.xpm [-.pixmaps]error.xpm \ + [-.pixmaps]generic.xpm [-.pixmaps]info.xpm [-.pixmaps]quest.xpm +gui_athena.obj : gui_athena.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h gui_at_sb.h +gui_gtk_x11.obj : gui_gtk_x11.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h gui_gtk_f.h [-.runtime]vim32x32.xpm \ + [-.runtime]vim16x16.xpm [-.runtime]vim48x48.xpm version.h +gui_x11.obj : gui_x11.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h [-.runtime]vim32x32.xpm \ + [-.runtime]vim16x16.xpm [-.runtime]vim48x48.xpm [-.pixmaps]tb_new.xpm \ + [-.pixmaps]tb_open.xpm [-.pixmaps]tb_close.xpm [-.pixmaps]tb_save.xpm \ + [-.pixmaps]tb_print.xpm [-.pixmaps]tb_cut.xpm [-.pixmaps]tb_copy.xpm \ + [-.pixmaps]tb_paste.xpm [-.pixmaps]tb_find.xpm \ + [-.pixmaps]tb_find_next.xpm [-.pixmaps]tb_find_prev.xpm \ + [-.pixmaps]tb_find_help.xpm [-.pixmaps]tb_exit.xpm \ + [-.pixmaps]tb_undo.xpm [-.pixmaps]tb_redo.xpm [-.pixmaps]tb_help.xpm \ + [-.pixmaps]tb_macro.xpm [-.pixmaps]tb_make.xpm \ + [-.pixmaps]tb_save_all.xpm [-.pixmaps]tb_jump.xpm \ + [-.pixmaps]tb_ctags.xpm [-.pixmaps]tb_load_session.xpm \ + [-.pixmaps]tb_save_session.xpm [-.pixmaps]tb_new_session.xpm \ + [-.pixmaps]tb_blank.xpm [-.pixmaps]tb_maximize.xpm \ + [-.pixmaps]tb_split.xpm [-.pixmaps]tb_minimize.xpm \ + [-.pixmaps]tb_shell.xpm [-.pixmaps]tb_replace.xpm \ + [-.pixmaps]tb_vsplit.xpm [-.pixmaps]tb_maxwidth.xpm \ + [-.pixmaps]tb_minwidth.xpm +gui_at_sb.obj : gui_at_sb.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h gui_at_sb.h +gui_at_fs.obj : gui_at_fs.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h gui_at_sb.h +pty.obj : pty.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h +if_perl.obj : [.auto]if_perl.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +if_perlsfio.obj : if_perlsfio.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +if_python.obj : if_python.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +if_tcl.obj : if_tcl.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +if_ruby.obj : if_ruby.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +if_lua.obj : if_lua.c vim.h [.auto]config.h feature.h os_unix.h \ + errors.h globals.h version.h +beval.obj : beval.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h option.h ex_cmds.h proto.h \ + errors.h globals.h +gui_beval.obj : gui_beval.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h +netbeans.obj : netbeans.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + errors.h globals.h version.h +gui_xmdlg.obj : gui_xmdlg.c [.auto]config.h vim.h feature.h os_unix.h +gui_xmebw.obj : gui_xmebw.c [.auto]config.h vim.h feature.h os_unix.h +xdiffi.obj : [.xdiff]xdiffi.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h +xemit.obj : [.xdiff]xemit.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h +xprepare.obj : [.xdiff]xprepare.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h +xutils.obj : [.xdiff]xutils.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h +xhistogram.obj : [.xdiff]xhistogram.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h +xpatience.obj : [.xdiff]xpatience.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..43249c2 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,4467 @@ +# Makefile for Vim on Unix and Unix-like systems vim:ts=8:sw=8:tw=78 +# +# This Makefile is loosely based on the GNU Makefile conventions found in +# standards.info. +# +# Compiling Vim, summary: +# +# 3. make +# 5. make install +# +# Compiling Vim, details: +# +# Edit this file for adjusting to your system. You should not need to edit any +# other file for machine specific things! +# The name of this file MUST be Makefile (note the uppercase 'M'). +# +# 1. Edit this Makefile {{{1 +# The defaults for Vim should work on most machines, but you may want to +# uncomment some lines or make other changes below to tune it to your +# system, compiler or preferences. Uncommenting means that the '#' in +# the first column of a line is removed. +# - If you want a version of Vim that is small and starts up quickly, +# you might want to disable the GUI, X11, Perl, Python and Tcl. +# - Uncomment the line with --disable-gui if you have Motif and/or GTK +# but don't want to make gvim (the GUI version of Vim with nice +# menus and scrollbars, but makes Vim bigger and startup slower). +# - Uncomment --disable-darwin if on Mac OS X but you want to compile a +# Unix version. +# - Uncomment the line "CONF_OPT_X = --without-x" if you have X11 but +# want to disable using X11 libraries. This speeds up starting Vim, +# but the window title will not be set and the X11 selection can not +# be used. +# - Uncomment the line "CONF_OPT_XSMP = --disable-xsmp" if you have the +# X11 Session Management Protocol (XSMP) library (libSM) but do not +# want to use it. +# This can speedup Vim startup but Vim loses the ability to catch the +# user logging out from session-managers like GNOME and work +# could be lost. +# - Uncomment one or more of these lines to include an interface; +# each makes Vim quite a bit bigger: +# --enable-luainterp for Lua interpreter +# --enable-mzschemeinterp for MzScheme interpreter +# --enable-perlinterp for Perl interpreter +# --enable-python3interp for Python3 interpreter +# --enable-pythoninterp for Python interpreter +# --enable-rubyinterp for Ruby interpreter +# --enable-tclinterp for Tcl interpreter +# --enable-cscope for Cscope interface +# - Uncomment one of the lines with --with-features= to enable a set of +# features (but not the interfaces just mentioned). +# - Uncomment the line with --disable-acl to disable ACL support even +# though your system supports it. +# - Uncomment the line with --disable-gpm to disable gpm support +# even though you have gpm libraries and includes. +# - Uncomment the line with --disable-sysmouse to disable sysmouse +# support even though you have /dev/sysmouse and includes. +# - Uncomment one of the lines with CFLAGS and/or CC if you have +# something very special or want to tune the optimizer. +# - Search for the name of your system to see if it needs anything +# special. +# - A few versions of make use '.include "file"' instead of 'include +# file'. Adjust the include line below if yours does. +# +# 2. Edit feature.h {{{1 +# Only if you do not agree with the default compile features, e.g.: +# - you want Vim to be as vi compatible as it can be +# - you want to use Emacs tags files +# - you want right-to-left editing (Hebrew) +# - you want 'langmap' support (Greek) +# - you want to remove features to make Vim smaller +# +# 3. "make" {{{1 +# Will first run ./configure with the options in this file. Then it will +# start make again on this Makefile to do the compiling. You can also do +# this in two steps with: +# make config +# make +# The configuration phase creates/overwrites auto/config.h and +# auto/config.mk. +# The configure script is created with "make autoconf". It can detect +# different features of your system and act accordingly. However, it is +# not correct for all systems. Check this: +# - If you have X windows, but configure could not find it or reported +# another include/library directory then you wanted to use, you have +# to set CONF_OPT_X below. You might also check the installation of +# xmkmf. +# - If you have --enable-gui=motif and have Motif on your system, but +# configure reports "checking for location of gui... ", you +# have to set GUI_INC_LOC and GUI_LIB_LOC below. +# If you changed something, do this to run configure again: +# make reconfig +# +# - If you do not trust the automatic configuration code, then inspect +# auto/config.h and auto/config.mk, before starting the actual build +# phase. If possible edit this Makefile, rather than auto/config.mk -- +# especially look at the definition of VIMLOC below. Note that the +# configure phase overwrites auto/config.mk and auto/config.h again. +# - If you get error messages, find out what is wrong and try to correct +# it in this Makefile. You may need to do "make reconfig" when you +# change anything that configure uses (e.g. switching from an old C +# compiler to an ANSI C compiler). Only when auto/configure does +# something wrong you may need to change one of the other files. If +# you find a clean way to fix the problem, consider sending a note to +# the author of autoconf (bug-gnu-utils@prep.ai.mit.edu) or Vim +# (Bram@vim.org). Don't bother to do that when you made a hack +# solution for a non-standard system. +# +# 4. "make test" {{{1 +# This is optional. This will run Vim scripts on a number of test +# files, and compare the produced output with the expected output. +# If all is well, you will get the "ALL DONE" message in the end. If a +# test fails you get "TEST FAILURE". See below (search for "/^test"). +# +# 5. "make install" {{{1 +# If the new Vim seems to be working OK you can install it and the +# documentation in the appropriate location. The default is +# "/usr/local". Change "prefix" below to change the location. +# "auto/pathdef.c" will be compiled again after changing this to make +# the executable know where the help files are located. +# Note that any existing executable is removed or overwritten. If you +# want to keep it you will have to make a backup copy first. +# The runtime files are in a different directory for each version. You +# might want to delete an older version. +# If you don't want to install everything, there are other targets: +# make installvim only installs Vim, not the tools +# make installvimbin only installs the Vim executable +# make installruntime installs most of the runtime files +# make installrtbase only installs the Vim help and +# runtime files +# make installlinks only installs the Vim binary links +# make installmanlinks only installs the Vim manpage links +# make installmacros only installs the Vim macros +# make installpack only installs the packages +# make installtutorbin only installs the Vim tutor program +# make installtutor only installs the Vim tutor files +# make installspell only installs the spell files +# make installtools only installs xxd +# If you install Vim, not to install for real but to prepare a package +# or RPM, set DESTDIR to the root of the tree. +# +# 6. Use Vim until a new version comes out. {{{1 +# +# 7. "make uninstall_runtime" {{{1 +# Will remove the runtime files for the current version. This is safe +# to use while another version is being used, only version-specific +# files will be deleted. +# To remove the runtime files of another version: +# make uninstall_runtime VIMRTDIR=/vim54 +# If you want to delete all installed files, use: +# make uninstall +# Note that this will delete files that have the same name for any +# version, thus you might need to do a "make install" soon after this. +# Be careful not to remove a version of Vim that is still being used! +# To find out which files and directories will be deleted, use: +# make -n uninstall +# }}} +# +### This Makefile has been successfully tested on many systems. {{{ +### Only the ones that require special options are mentioned here. +### Check the (*) column for remarks, listed below. +### Later code changes may cause small problems, otherwise Vim is supposed to +### compile and run without problems. + +#system: configurations: version (*) tested by: +#------------- ------------------------ ------- - ---------- +#AIX 3.2.5 cc (not gcc) - 4.5 (M) Will Fiveash +#AIX 4 cc +X11 -GUI 3.27 (4) Axel Kielhorn +#AIX 4.1.4 cc +X11 +GUI 4.5 (5) Nico Bakker +#AIX 4.2.1 cc 5.2k (C) Will Fiveash +#AIX 4.3.3.12 xic 3.6.6 5.6 (5) David R. Favor +#A/UX 3.1.1 gcc +X11 4.0 (6) Jim Jagielski +#BSDI 2.1 (x86) shlicc2 gcc-2.6.3 -X11 X11R6 4.5 (1) Jos Backus +#BSD/OS 3.0 (x86) gcc gcc-2.7.2.1 -X11 X11R6 4.6c (1) Jos Backus +#CX/UX 6.2 cc +X11 +GUI_Mofif 5.4 (V) Kipp E. Howard +#DG/UX 5.4* gcc 2.5.8 GUI 5.0e (H) Jonas Schlein +#DG/UX 5.4R4.20 gcc 2.7.2 GUI 5.0s (H) Rocky Olive +#HP-UX (most) c89 cc 5.1 (2) Bram Moolenaar +#HP-UX_9.04 cc +X11 +Motif 5.0 (2) Carton Lao +#Linux 2.0 gcc-2.7.2 Infomagic Motif 4.3 (3) Ronald Rietman +#NEC UP4800 UNIX_SV 4.2MP cc +X11R6 Motif 4.6b (Q) Lennart Schultz +#NetBSD 1.0A gcc-2.4.5 -X11 -GUI 3.21 (X) Juergen Weigert +#QNX 4.2 wcc386-10.6 -X11 4.2 (D) G.F. Desrochers +#QNX 4.23 Watcom -X11 4.2 (F) John Oleynick +#SCO Unix v3.2.5 cc +X11 Motif 3.27 (C) M. Kuperblum +#SCO Open Server 5 gcc 2.7.2.3 +X11 +GUI Motif 5.3 (A) Glauber Ribeiro +#SINIX-N 5.43 RM400 R4000 cc +X11 +GUI 5.0l (I) Martin Furter +#SINIX-Z 5.42 i386 gcc 2.7.2.3 +X11 +GUI Motif 5.1 (I) Joachim Fehn +#SINIX-Y 5.43 RM600 R4000 gcc 2.7.2.3 +X11 +GUI Motif 5.1 (I) Joachim Fehn +#Reliant/SINIX 5.44 cc +X11 +GUI 5.5a (I) B. Pruemmer +#SNI Targon31 TOS 4.1.11 gcc-2.4.5 +X11 -GUI 4.6c (B) Paul Slootman +#Solaris 2.4 (Sparc) cc +X11 +GUI 3.29 (9) Glauber +#Solaris 2.4/2.5 clcc +X11 -GUI openwin 3.20 (7) Robert Colon +#Solaris 2.5 (sun4m) cc (SC4.0) +X11R6 +GUI (CDE) 4.6b (E) Andrew Large +#Solaris 2.5 gcc 2.5.6 +X11 Motif 5.0m (R) Ant. Colombo +#Solaris 2.6 gcc 2.8.1 ncurses 5.3 (G) Larry W. Virden +#Solaris with -lthread 5.5 (W) K. Nagano +#Solaris gcc (b) Riccardo +#SunOS 4.1.x +X11 -GUI 5.1b (J) Bram Moolenaar +#SUPER-UX 6.2 (NEC SX-4) cc +X11R6 Motif 4.6b (P) Lennart Schultz +#Tandem/NSK (c) Matthew Woehlke +#Unisys 6035 cc +X11 Motif 5.3 (8) Glauber Ribeiro +#ESIX V4.2 cc +X11 6.0 (a) Reinhard Wobst +# }}} + +# (*) Remarks: {{{ +# +# (1) Uncomment line below for shlicc2 +# (2) HPUX with compile problems or wrong digraphs, uncomment line below +# (3) Infomagic Motif needs GUI_LIB_LOC and GUI_INC_LOC set, see below. +# And add "-lXpm" to MOTIF_LIBS2. +# (4) For cc the optimizer must be disabled (use CFLAGS= after running +# configure) (symptom: ":set termcap" output looks weird). +# (5) Compiler may need extra argument, see below. +# (6) See below for a few lines to uncomment +# (7) See below for lines which enable the use of clcc +# (8) Needs some EXTRA_LIBS, search for Unisys below +# (9) Needs an extra compiler flag to compile gui_at_sb.c, see below. +# (A) May need EXTRA_LIBS, see below +# (B) Can't compile GUI because there is no waitpid()... Disable GUI below. +# (C) Force the use of curses instead of termcap, see below. +# (D) Uncomment lines below for QNX +# (E) You might want to use termlib instead of termcap, see below. +# (F) See below for instructions. +# (G) Using ncurses version 4.2 has reported to cause a crash. Use the +# Sun curses library instead. +# (H) See line for EXTRA_LIBS below. +# (I) SINIX-N 5.42 and 5.43 need some EXTRA_LIBS. Also for Reliant-Unix. +# (J) If you get undefined symbols, see below for a solution. +# (K) See lines to uncomment below for machines with 64 bit pointers. +# (L) For Silicon Graphics O2 workstations remove "-lnsl" from auto/config.mk +# (M) gcc version cygnus-2.0.1 does NOT work (symptom: "dl" deletes two +# characters instead of one). +# (N) SCO with decmouse. +# (O) LynxOS needs EXTRA_LIBS, see below. +# (P) For SuperUX 6.2 on NEC SX-4 see a few lines below to uncomment. +# (Q) For UNIXSVR 4.2MP on NEC UP4800 see below for lines to uncomment. +# (R) For Solaris 2.5 (or 2.5.1) with gcc > 2.5.6, uncomment line below. +# (U) Must uncomment CONF_OPT_PYTHON option below to disable Python +# detection, since the configure script runs into an error when it +# detects Python (probably because of the bash shell). +# (V) See lines to uncomment below. +# (X) Need to use the .include "auto/config.mk" line below +# (Y) See line with c89 below +# (Z) See lines with cc or c89 below +# (a) See line with EXTRA_LIBS below. +# (b) When using gcc with the Solaris linker, make sure you don't use GNU +# strip, otherwise the binary may not run: "Cannot find ELF". +# (c) Add -lfloss to EXTRA_LIBS, see below. +# (x) When you get warnings for precompiled header files, run +# "sudo fixPrecomps". Also see CONF_OPT_DARWIN below. +# }}} + + +#DO NOT CHANGE the next line, we need it for configure to find the compiler +#instead of using the default from the "make" program. +#Use a line further down to change the value for CC. +CC= + +# Change and use these defines if configure cannot find your Motif stuff. +# Unfortunately there is no "standard" location for Motif. {{{ +# These defines can contain a single directory (recommended) or a list of +# directories (for when you are working with several systems). The LAST +# directory that exists is used. +# When changed, run "make reconfig" next! +#GUI_INC_LOC = -I/usr/include/Motif2.0 -I/usr/include/Motif1.2 +#GUI_LIB_LOC = -L/usr/lib/Motif2.0 -L/usr/lib/Motif1.2 +### Use these two lines for Infomagic Motif (3) +#GUI_INC_LOC = -I/usr/X11R6/include +#GUI_LIB_LOC = -L/usr/X11R6/lib +# }}} + +# Defaults used when auto/config.mk does not exist. +srcdir = . +VIMNAME = vim +EXNAME = ex +VIEWNAME = view + +######################## auto/config.mk ######################## {{{1 +# At this position auto/config.mk is included. When starting from the +# toplevel Makefile it is almost empty. After running auto/configure it +# contains settings that have been discovered for your system. Settings below +# this include override settings in auto/config.mk! + +# Note: If make fails because auto/config.mk does not exist (it is not +# included in the repository), do: +# cp config.mk.dist auto/config.mk + +# (X) How to include auto/config.mk depends on the version of "make" you have, +# if the current choice doesn't work, try the other one. + +include auto/config.mk +#.include "auto/config.mk" +CClink = $(CC) + +#}}} + +# Include the configuration choices first, so we can override everything +# below. As shipped, this file contains a target that causes to run +# configure. Once configure was run, this file contains a list of +# make variables with predefined values instead. Thus any second invocation +# of make, will build Vim. + +# CONFIGURE - configure arguments {{{1 +# You can give a lot of options to configure. +# Change this to your desire and do 'make config' afterwards + +# examples you can uncomment: +#CONF_ARGS1 = --exec-prefix=/usr +#CONF_ARGS2 = --with-vim-name=vim8 --with-ex-name=ex8 --with-view-name=view8 +#CONF_ARGS3 = --with-global-runtime=/etc/vim,/usr/share/vim +#CONF_ARGS4 = --with-local-dir=/usr/share +#CONF_ARGS5 = --without-local-dir + +# Use this one if you distribute a modified version of Vim. +#CONF_ARGS6 = --with-modified-by="John Doe" + +# GUI - For creating Vim with GUI (gvim) (B) +# Uncomment this line when you don't want to get the GUI version, although you +# have GTK and/or Motif. Also use --without-x if you don't want X11 +# at all. +#CONF_OPT_GUI = --disable-gui + +# Uncomment one of these lines if you have that GUI but don't want to use it. +# The automatic check will use another one that can be found. +# Gnome is disabled by default, because it may cause trouble. +# +# When both GTK+ 2 and GTK+ 3 are possible then GTK+ 2 will be selected. +# To use GTK+ 3 instead use --enable-gui=gtk3 (see below). +#CONF_OPT_GUI = --disable-gtk2-check +#CONF_OPT_GUI = --enable-gnome-check +#CONF_OPT_GUI = --disable-gtk3-check +#CONF_OPT_GUI = --disable-motif-check + +# Uncomment one of these lines to select a specific GUI to use. +# When using "yes" or nothing, configure will use the first one found: GTK+, +# or Motif. +# +# GTK versions that are known not to work 100% are rejected. +# Use "--disable-gtktest" to accept them anyway. +# For GTK 1 use Vim 7.2. +# +# GNOME means GTK with Gnome support. If using GTK and --enable-gnome-check +# is used then GNOME will automatically be used if it is found. If you have +# GNOME, but do not want to use it (e.g., want a GTK-only version), then use +# --enable-gui=gtk or leave out --enable-gnome-check. +# +# GNOME makes sense only for GTK+ 2. Avoid use of --enable-gnome-check with +# GTK+ 3 build, as the functionality of GNOME is already incooperated into +# GTK+ 3. +# +# If the selected GUI isn't found, the GUI is disabled automatically +#CONF_OPT_GUI = --enable-gui=gtk2 +#CONF_OPT_GUI = --enable-gui=gtk2 --disable-gtktest +#CONF_OPT_GUI = --enable-gui=gnome2 +#CONF_OPT_GUI = --enable-gui=gnome2 --disable-gtktest +#CONF_OPT_GUI = --enable-gui=gtk3 +#CONF_OPT_GUI = --enable-gui=gtk3 --disable-gtktest +#CONF_OPT_GUI = --enable-gui=motif +#CONF_OPT_GUI = --enable-gui=motif --with-motif-lib="-static -lXm -shared" + +# Uncomment this line to run an individual test with gvim. +#GUI_TESTARG = GUI_FLAG=-g + +# DARWIN - detecting Mac OS X +# Uncomment this line when you want to compile a Unix version of Vim on +# Darwin. None of the Mac specific options or files will be used. +#CONF_OPT_DARWIN = --disable-darwin + +# Select the architecture supported. Default is to build for the current +# platform. Use "both" for a universal binary. That probably doesn't work +# when including Perl, Python, etc. +# NOTE: ppc probably doesn't work anymore, +#CONF_OPT_DARWIN = --with-mac-arch=intel +#CONF_OPT_DARWIN = --with-mac-arch=ppc +#CONF_OPT_DARWIN = --with-mac-arch=both + +# Uncomment the next line to fail if one of the requested language interfaces +# cannot be configured. Without this Vim will be build anyway, without +# the failing interfaces. +#CONF_OPT_FAIL = --enable-fail-if-missing + +# LUA +# Uncomment one of these when you want to include the Lua interface. +# First one is for static linking, second one for dynamic loading. +# Debian package is "lua5.3" and "liblua5.3-dev" or "lua5.4" and +# "liblua5.4-dev". +# Use --with-luajit if you want to use LuaJIT instead of Lua. +# Set PATH environment variable to find lua or luajit executable. +# This requires at least "normal" features, "tiny" doesn't work. +#CONF_OPT_LUA = --enable-luainterp +#CONF_OPT_LUA = --enable-luainterp=dynamic +#CONF_OPT_LUA = --enable-luainterp --with-luajit +#CONF_OPT_LUA = --enable-luainterp=dynamic --with-luajit +# Lua installation dir (when not set uses $LUA_PREFIX or defaults to /usr) +#CONF_OPT_LUA_PREFIX = --with-lua-prefix=/usr/local + +# MZSCHEME +# Uncomment this when you want to include the MzScheme interface. +# You may have to build racket from source to make this work. Version 7.9 has +# been reported to work, version 8.0 probably doesn't work, version 8.5 has +# been reported to work. +# NOTE: does not work well together with valgrind. +#CONF_OPT_MZSCHEME = --enable-mzschemeinterp +# PLT/mrscheme/drscheme Home dir; the PLTHOME environment variable also works +#CONF_OPT_PLTHOME = --with-plthome=/usr/local +#CONF_OPT_PLTHOME = --with-plthome=/usr/local/plt +#CONF_OPT_PLTHOME = --with-plthome=/usr/local/drscheme +#CONF_OPT_PLTHOME = --with-plthome=/home/me/mz + +# PERL +# Uncomment one of these when you want to include the Perl interface. +# First one is for static linking, second one for dynamic loading. +# Debian package is "libperl-dev" +# The Perl option sometimes causes problems, because it adds extra flags +# to the command line. If you see strange flags during compilation, check in +# auto/config.mk where they come from. If it's PERL_CFLAGS, try commenting +# the next line. +# When you get an error for a missing "perl.exp" file, try creating an empty +# one: "touch perl.exp". +# This requires at least "normal" features, "tiny" doesn't work. +#CONF_OPT_PERL = --enable-perlinterp +#CONF_OPT_PERL = --enable-perlinterp=dynamic + +# PYTHON +# Uncomment lines here when you want to include the Python interface. +# Debian package is "libpython3-dev". +# This requires at least "normal" features, "tiny" doesn't work. +# Python 3 is preferred, Python 2 (often referred to as "Python") has been +# deprecated for a long time. +# NOTE: This may cause threading to be enabled, which has side effects (such +# as using different libraries and debugging becomes more difficult). +# For Python3 support make a symbolic link in /usr/local/bin: +# ln -s python3 python3.1 +# If both python2.x and python3.x are enabled then the linking will be via +# dlopen(), dlsym(), dlclose(), i.e. pythonX.Y.so must be available +# However, this may still cause problems, such as "import termios" failing. +# Build two separate versions of Vim in that case. +#CONF_OPT_PYTHON = --enable-pythoninterp +#CONF_OPT_PYTHON = --enable-pythoninterp --with-python-command=python2.7 +#CONF_OPT_PYTHON = --enable-pythoninterp=dynamic +#CONF_OPT_PYTHON3 = --enable-python3interp +#CONF_OPT_PYTHON3 = --enable-python3interp --with-python3-command=python3.6 +#CONF_OPT_PYTHON3 = --enable-python3interp=dynamic + +# RUBY +# Uncomment this when you want to include the Ruby interface. +# First one for static linking, second one for loading when used. +# Debian package is "ruby-dev". +# This requires at least "normal" features, "tiny" doesn't work. +#CONF_OPT_RUBY = --enable-rubyinterp +#CONF_OPT_RUBY = --enable-rubyinterp=dynamic +#CONF_OPT_RUBY = --enable-rubyinterp --with-ruby-command=ruby1.9.1 + +# TCL +# Uncomment this when you want to include the Tcl interface. +# First one is for static linking, second one for dynamic loading. +# Debian package is "tcl-dev". +#CONF_OPT_TCL = --enable-tclinterp +#CONF_OPT_TCL = --enable-tclinterp=dynamic +#CONF_OPT_TCL = --enable-tclinterp --with-tclsh=tclsh8.4 + +# CSCOPE +# Uncomment this when you want to include the Cscope interface. +#CONF_OPT_CSCOPE = --enable-cscope + +# NETBEANS - NetBeans interface. Only works with Motif, GTK, and gnome. +# Motif version must have XPM libraries (see |netbeans-xpm|). +# Uncomment this when you do not want the netbeans interface. +#CONF_OPT_NETBEANS = --disable-netbeans + +# CHANNEL - inter process communication. Same conditions as NetBeans. +# Uncomment this when you do not want inter process communication. +#CONF_OPT_CHANNEL = --disable-channel + +# TERMINAL - Terminal emulator support, :terminal command. Requires the +# channel feature. The default is enable for when using "huge" features. +# Uncomment the first line when you want terminal emulator support for +# not-huge builds. Uncomment the second line when you don't want terminal +# emulator support in the huge build. +#CONF_OPT_TERMINAL = --enable-terminal +#CONF_OPT_TERMINAL = --disable-terminal + +# MULTIBYTE - To edit multi-byte characters. +# This is now always enabled. + +# When building with "huge" features, right-left and Arabic +# features are enabled. Use this to disable them. +#CONF_OPT_MULTIBYTE = --disable-rightleft --disable-arabic + +# NLS - National Language Support +# Uncomment this when you do not want to support translated messages, even +# though configure can find support for it. +#CONF_OPT_NLS = --disable-nls + +# XIM - X Input Method. Special character input support for X11 (Chinese, +# Japanese, special symbols, etc). Also needed for dead-key support. +# When omitted it's automatically enabled for the X-windows GUI. +#CONF_OPT_INPUT = --enable-xim +#CONF_OPT_INPUT = --disable-xim + +# FONTSET - X fontset support for output of languages with many characters. +# Uncomment this when you want to output a multibyte language. +#CONF_OPT_OUTPUT = --enable-fontset + +# ACL - Uncomment this when you do not want to include ACL support, even +# though your system does support it. E.g., when it's buggy. +#CONF_OPT_ACL = --disable-acl + +# gpm - For mouse support on Linux console via gpm +# Uncomment this when you do not want to include gpm support, even +# though you have gpm libraries and includes. +# For Debian/Ubuntu gpm support requires the libgpm-dev package. +#CONF_OPT_GPM = --disable-gpm +# Use this to enable dynamic loading of the GPM library. +#CONF_OPT_GPM = --enable-gpm=dynamic + +# sysmouse - For mouse support on FreeBSD and DragonFly console via sysmouse +# Uncomment this when you do not want do include sysmouse support, even +# though you have /dev/sysmouse and includes. +#CONF_OPT_SYSMOUSE = --disable-sysmouse + +# libcanberra - For sound support. Default is on for huge features. +# Uncomment one of the two to chose otherwise. +# CONF_OPT_CANBERRA = --enable-canberra +# CONF_OPT_CANBERRA = --disable-canberra + +# libsodium - For enhanced encryption. Default is on. +# Uncomment the next line to not use libsodium +# CONF_OPT_SODIUM = --disable-libsodium + +# FEATURES - For creating Vim with more or less features +# Uncomment one of these lines when you want to include few to many features. +# The default is "huge" for most systems. +#CONF_OPT_FEAT = --with-features=tiny +#CONF_OPT_FEAT = --with-features=normal +#CONF_OPT_FEAT = --with-features=huge + +# COMPILED BY - For including a specific e-mail address for ":version". +#CONF_OPT_COMPBY = "--with-compiledby=John Doe " + +# X WINDOWS DISABLE - For creating a plain Vim without any X11 related fancies +# (otherwise Vim configure will try to include xterm titlebar access) +# Also disable the GUI above, otherwise it will be included anyway. +# When both GUI and X11 have been disabled this may save about 15% of the +# code and make Vim startup quicker. +#CONF_OPT_X = --without-x + +# X WINDOWS DIRECTORY - specify X directories +# If configure can't find you X stuff, or if you have multiple X11 derivatives +# installed, you may wish to specify which one to use. +# Select nothing to let configure choose. +# This here selects openwin (as found on sun). +#XROOT = /usr/openwin +#CONF_OPT_X = --x-include=$(XROOT)/include --x-libraries=$(XROOT)/lib + +# X11 Session Management Protocol support +# Vim will try to use XSMP to catch the user logging out if there are unsaved +# files. Uncomment this line to disable that (it prevents vim trying to open +# communications with the session manager). +#CONF_OPT_XSMP = --disable-xsmp + +# You may wish to include xsmp but use exclude xsmp-interact if the logout +# XSMP functionality does not work well with your session-manager (at time of +# writing, this would be early GNOME-1 gnome-session: it 'freezes' other +# applications after Vim has cancelled a logout (until Vim quits). This +# *might* be the Vim code, but is more likely a bug in early GNOME-1. +# This disables the dialog that asks you if you want to save files or not. +#CONF_OPT_XSMP = --disable-xsmp-interact + +# If you want to always automatically add a servername, also in the terminal. +#CONF_OPT_AUTOSERVE = --enable-autoservername + +# COMPILER - Name of the compiler {{{1 +# The default from configure will mostly be fine, no need to change this, just +# an example. If a compiler is defined here, configure will use it rather than +# probing for one. It is dangerous to change this after configure was run. +# Make will use your choice then -- but beware: Many things may change with +# another compiler. It is wise to run 'make reconfig' to start all over +# again. +#CC = cc +#CC = gcc +#CC = clang + +# COMPILER FLAGS - change as you please. Either before running {{{1 +# configure or afterwards. For examples see below. +# When using -g with some older versions of Linux you might get a +# statically linked executable. +# When not defined, configure will try to use -O2 -g for gcc and -O for cc. +#CFLAGS = -g +#CFLAGS = -O + +# Optimization limits - depends on the compiler. Automatic check in configure +# doesn't work very well, because many compilers only give a warning for +# unrecognized arguments. +#CFLAGS = -O -OPT:Olimit=2600 +#CFLAGS = -O -Olimit 2000 +#CFLAGS = -O -FOlimit,2000 + +# Often used for GCC: mixed optimizing, lot of optimizing, debugging +#CFLAGS = -g -O2 -fno-strength-reduce -Wall -Wshadow -Wmissing-prototypes +#CFLAGS = -g -O2 -fno-strength-reduce -Wall -Wmissing-prototypes +#CFLAGS = -g -Wall -Wmissing-prototypes +#CFLAGS = -O6 -fno-strength-reduce -Wall -Wshadow -Wmissing-prototypes +#CFLAGS = -g -DDEBUG -Wall -Wshadow -Wmissing-prototypes +#CFLAGS = -g -O2 '-DSTARTUPTIME="vimstartup"' -fno-strength-reduce -Wall -Wmissing-prototypes + +# Use this with GCC to check for mistakes, unused arguments, etc. +# Note: If you use -Wextra and get warnings in GTK code about function +# parameters, you can add -Wno-cast-function-type (but not with clang) +#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -Wno-cast-function-type -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 +#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -Wno-deprecated-declarations -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 +# Add -Wpedantic to find // comments and other C99 constructs. +# Better disable Perl and Python to avoid a lot of warnings. +#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wunused-result -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 +#CFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wno-cast-function-type -Wunused-result -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 +#PYTHON_CFLAGS_EXTRA = -Wno-missing-field-initializers +#MZSCHEME_CFLAGS_EXTRA = -Wno-unreachable-code -Wno-unused-parameter + +# EFENCE - Electric-Fence malloc debugging: catches memory accesses beyond +# allocated memory (and makes every malloc()/free() very slow). +# Electric Fence is free (search ftp sites). +# You may want to set the EF_PROTECT_BELOW environment variable to check the +# other side of allocated memory. +# On FreeBSD you might need to enlarge the number of mmaps allowed. Do this +# as root: sysctl -w vm.max_proc_mmap=30000 +#EXTRA_LIBS = /usr/local/lib/libefence.a + +# Autoconf binary. +AUTOCONF = autoconf + +# PURIFY - remove the # to use the "purify" program (hoi Nia++!) +#PURIFY = purify + +# VALGRIND - remove the # to use valgrind for memory leaks and access errors. +# Used for the unittest targets. +# VALGRIND = valgrind --tool=memcheck --leak-check=yes --num-callers=25 --log-file=valgrind.$@ + +# NBDEBUG - debugging the netbeans interface. +#EXTRA_DEFS = -DNBDEBUG + +# }}} + +# LINT - for running lint +# For standard Unix lint +LINT = lint +LINT_OPTIONS = -beprxzF +# For splint +# It doesn't work well, crashes on include files and non-ascii characters. +#LINT = splint +#LINT_OPTIONS = +unixlib -weak -macrovarprefixexclude -showfunc -linelen 9999 + +# PROFILING - Uncomment the next two lines to do profiling with gcc and gprof. +# Might not work with GUI or Perl. +# After running Vim see the profile result with: gprof vim gmon.out | vim - +# Need to recompile everything after changing this: "make clean" "make". +#PROFILE_CFLAGS = -pg -g -DWE_ARE_PROFILING +#PROFILE_LIBS = -pg + +# GCC 5 and later need the -no-pie argument. +#PROFILE_LIBS = -pg -no-pie + +# For unknown reasons adding "-lc" fixes a linking problem with some versions +# of GCC. That's probably a bug in the "-pg" implementation. +#PROFILE_LIBS = -pg -lc + + +# TEST COVERAGE - Uncomment the two lines below the explanation to get code +# coverage information. (provided by Yegappan Lakshmanan) +# 1. make clean, run configure and build Vim as usual. +# 2. Generate the baseline code coverage information: +# $ lcov -c -i -b . -d objects -o objects/coverage_base.info +# 3. Run "make test" to run the unit tests. The code coverage information will +# be generated in the src/objects directory. +# 4. Generate the code coverage information from the tests: +# $ lcov -c -b . -d objects/ -o objects/coverage_test.info +# 5. Combine the baseline and test code coverage data: +# $ lcov -a objects/coverage_base.info -a objects/coverage_test.info -o objects/coverage_total.info +# 6. Process the test coverage data and generate a report in html: +# $ genhtml objects/coverage_total.info -o objects +# 7. Open the objects/index.html file in a web browser to view the coverage +# information. +# +# LDFLAGS=--coverage +# PROFILE_CFLAGS=-g -O0 -fprofile-arcs -ftest-coverage -DWE_ARE_PROFILING -DUSE_GCOV_FLUSH +# Alternate flags +# PROFILE_CFLAGS=-g -O0 --coverage -DWE_ARE_PROFILING -DUSE_GCOV_FLUSH + + +# Uncomment the next lines to compile Vim with the address sanitizer (asan) and +# with the undefined sanitizer. Works with gcc. +# You should also use -DEXITFREE to avoid false reports. +# May make Vim twice as slow. Errors are reported on stderr. +# More at: https://code.google.com/p/address-sanitizer/ +# Useful environment variables: +# $ export ASAN_OPTIONS="print_stacktrace=1 log_path=asan" +# $ export LSAN_OPTIONS="suppressions=`pwd`/testdir/lsan-suppress.txt" +# When running tests output can be found in testdir/asan.* +#SANITIZER_CFLAGS = -g -O0 -fsanitize-recover=all \ +# -fsanitize=address -fsanitize=undefined \ +# -fno-omit-frame-pointer + +# Similarly when compiling with clang and using ubsan. +# $ export UBSAN_OPTIONS="print_stacktrace=1 log_path=ubsan" +# $ export LSAN_OPTIONS="suppressions=`pwd`/testdir/lsan-suppress.txt" +# When running tests output can be found in testdir/ubsan.* +#SANITIZER_CFLAGS = -g -O0 -fsanitize-recover=all -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer + +SANITIZER_LIBS = $(SANITIZER_CFLAGS) + +# MEMORY LEAK DETECTION +# Requires installing the ccmalloc library. +# Configuration is in the .ccmalloc or ~/.ccmalloc file. +# Doesn't work very well, since memory linked to from global variables +# (in libraries) is also marked as leaked memory. +#LEAK_CFLAGS = -DEXITFREE +#LEAK_LIBS = -lccmalloc + +# Uncomment this line to have Vim call abort() when an internal error is +# detected. Useful when using a tool to find errors. +#ABORT_CFLAGS = -DABORT_ON_INTERNAL_ERROR + +#################################################### +### Specific systems, check if yours is listed ### {{{ +#################################################### + +### Uncomment things here only if the values chosen by configure are wrong. +### It's better to adjust configure.ac and "make autoconf", if you can! +### Then send the required changes to configure.ac to the bugs list. + +### (1) BSD/OS 2.0.1, 2.1 or 3.0 using shared libraries +### +#CC = shlicc2 +#CFLAGS = -O2 -g -m486 -Wall -Wshadow -Wmissing-prototypes -fno-builtin + +### (2) HP-UX with a non-ANSI cc, use the c89 ANSI compiler +### The first probably works on all systems +### The second should work a bit better on newer systems +### The third should work a bit better on HPUX 11.11 +### Information provided by: Richard Allen +#CC = c89 -D_HPUX_SOURCE +#CC = c89 -O +Onolimit +ESlit -D_HPUX_SOURCE +#CC = c89 -O +Onolimit +ESlit +e -D_HPUX_SOURCE + +### (2) For HP-UX: 9.04 cpp default macro definition table of 128000 bytes +### is too small to compile many routines. It produces too much defining +### and no space errors. +### Uncomment the following to specify a larger macro definition table. +#CFLAGS = -Wp,-H256000 + +### (2) For HP-UX 10.20 using the HP cc, with X11R6 and Motif 1.2, with +### libraries in /usr/lib instead of /lib (avoiding transition links). +### Information provided by: David Green +#XROOT = /usr +#CONF_OPT_X = --x-include=$(XROOT)/include/X11R6 --x-libraries=$(XROOT)/lib/X11R6 +#GUI_INC_LOC = -I/usr/include/Motif1.2 +#GUI_LIB_LOC = -L/usr/lib/Motif1.2_R6 + +### (5) AIX 4.1.4 with cc +#CFLAGS = -O -qmaxmem=8192 + +### AIX with c89 (Walter Briscoe) +#CC = c89 +#CPPFLAGS = -D_ALL_SOURCE + +### AIX 4.3.3.12 with xic 3.6.6 (David R. Favor) +# needed to avoid a problem where strings.h gets included +#CFLAGS = -qsrcmsg -O2 -qmaxmem=8192 -D__STR31__ + +### (7) Solaris 2.4/2.5 with Centerline compiler +#CC = clcc +#X_LIBS_DIR = -L/usr/openwin/lib -R/usr/openwin/lib +#CFLAGS = -O + +### Solaris 2.3 with X11 and specific cc +#CC=/opt/SUNWspro/bin/cc -O -Xa -v -R/usr/openwin/lib + +### Solaris with /usr/ucb/cc (it is rejected by autoconf as "cc") +#CC = /usr/ucb/cc +#EXTRA_LIBS = -R/usr/ucblib + +### Solaris with Forte Developer and NetBeans. +# The Xpm library is available from http://koala.ilog.fr/ftp/pub/xpm. +#CC = cc +#XPM_DIR = /usr/local/xpm/xpm-3.4k-solaris +#XPM_LIB = -L$(XPM_DIR)/lib -R$(XPM_DIR)/lib -lXpm +#XPM_IPATH = -I$(XPM_DIR)/include +#EXTRA_LIBS = $(XPM_LIB) +#EXTRA_IPATHS = $(XPM_IPATH) +#EXTRA_DEFS = -xCC -DHAVE_X11_XPM_H + +### (R) for Solaris 2.5 (or 2.5.1) with gcc > 2.5.6 you might need this: +#LDFLAGS = -lw -ldl -lXmu +#GUI_LIB_LOC = -L/usr/local/lib + +### (8) Unisys 6035 (Glauber Ribeiro) +#EXTRA_LIBS = -lnsl -lsocket -lgen + +### When builtin functions cause problems with gcc (for Sun 4.1.x) +#CFLAGS = -O2 -Wall -traditional -Wno-implicit + +### Apollo DOMAIN (with SYSTYPE = bsd4.3) (TESTED for version 3.0) +#EXTRA_DEFS = -DDOMAIN +#CFLAGS= -O -A systype,bsd4.3 + +### Coherent 4.2.10 on Intel 386 platform +#EXTRA_DEFS = -Dvoid=int +#EXTRA_LIBS = -lterm -lsocket + +### SCO 3.2, with different library name for terminfo +#EXTRA_LIBS = -ltinfo + +### UTS2 for Amdahl UTS 2.1.x +#EXTRA_DEFS = -DUTS2 +#EXTRA_LIBS = -lsocket + +### UTS4 for Amdahl UTS 4.x +#EXTRA_DEFS = -DUTS4 -Xa + +### USL for Unix Systems Laboratories (SYSV 4.2) +#EXTRA_DEFS = -DUSL + +### (6) A/UX 3.1.1 with gcc (Jim Jagielski) +#CC= gcc -D_POSIX_SOURCE +#CFLAGS= -O2 +#EXTRA_LIBS = -lposix -lbsd -ltermcap -lX11 + +### (A) Some versions of SCO Open Server 5 (Jan Christiaan van Winkel) +### Also use the CONF_TERM_LIB below! +#EXTRA_LIBS = -lgen + +### (D) QNX (by G.F. Desrochers) +#CFLAGS = -g -O -mf -4 + +### (F) QNX (by John Oleynick) +# 1. If you don't have an X server: Comment out CONF_OPT_GUI and uncomment +# CONF_OPT_X = --without-x. +# 2. make config +# 3. edit auto/config.mk and remove -ldir and -ltermcap from LIBS. It doesn't +# have -ldir (does config find it somewhere?) and -ltermcap has at +# least one problem so I use termlib.o instead. The problem with +# termcap is that it segfaults if you call it with the name of +# a non-existent terminal type. +# 4. edit auto/config.h and add #define USE_TMPNAM +# 5. add termlib.o to OBJ +# 6. make + +### (H) for Data general DG/UX 5.4.2 and 5.4R3.10 (Jonas J. Schlein) +#EXTRA_LIBS = -lgen + +### (I) SINIX-N 5.42 or 5.43 RM400 R4000 (also SINIX-Y and SINIX-Z) +#EXTRA_LIBS = -lgen -lnsl +### For SINIX-Y this is needed for the right prototype of gettimeofday() +#EXTRA_DEFS = -D_XPG_IV + +### (I) Reliant-Unix (aka SINIX) 5.44 with standard cc +# Use both "-F O3" lines for optimization or the "-g" line for debugging +#EXTRA_LIBS = -lgen -lsocket -lnsl -lSM -lICE +#CFLAGS = -F O3 -DSINIXN +#LDFLAGS = -F O3 +#CFLAGS = -g -DSINIXN + +### (P) SCO 3.2.42, with different termcap names for some useful keys DJB +#EXTRA_DEFS = -DSCOKEYS -DNETTERM_MOUSE -DDEC_MOUSE -DXTERM_MOUSE -DHAVE_GETTIMEOFDAY +#EXTRA_LIBS = -lsocket -ltermcap -lmalloc -lc_s + +### (P) SuperUX 6.2 on NEC SX-4 (Lennart Schultz) +#GUI_INC_LOC = -I/usr/include +#GUI_LIB_LOC = -L/usr/lib +#EXTRA_LIBS = -lgen + +### (Q) UNIXSVR 4.2MP on NEC UP4800 (Lennart Schultz) +#GUI_INC_LOC = -I/usr/necccs/include +#GUI_LIB_LOC = -L/usr/necccs/lib/X11R6 +#XROOT = /usr/necccs +#CONF_OPT_X = --x-include=$(XROOT)/include --x-libraries=$(XROOT)/lib/X11R6 +#EXTRA_LIBS = -lsocket -lgen + +### (C) On SCO Unix v3.2.5 (and probably other versions) the termcap library, +### which is found by configure, doesn't work correctly. Symptom is the +### error message "Termcap entry too long". Uncomment the next line. +### On AIX 4.2.1 (and other versions probably), libtermcap is reported +### not to display properly. +### after changing this, you need to do "make reconfig". +#CONF_TERM_LIB = --with-tlib=curses + +### (E) If you want to use termlib library instead of the automatically found +### one. After changing this, you need to do "make reconfig". +#CONF_TERM_LIB = --with-tlib=termlib + +### (a) ESIX V4.2 (Reinhard Wobst) +#EXTRA_LIBS = -lnsl -lsocket -lgen -lXIM -lXmu -lXext + +### (c) Tandem/NSK (Matthew Woehlke) +#EXTRA_LIBS = -lfloss + +### If you want to use ncurses library instead of the automatically found one +### after changing this, you need to do "make reconfig". +#CONF_TERM_LIB = --with-tlib=ncurses + +### For GCC on MS-Windows, the ".exe" suffix will be added. +#EXEEXT = .exe +#LNKEXT = .exe + +### (O) For LynxOS 2.5.0, tested on PC. +#EXTRA_LIBS = -lXext -lSM -lICE -lbsd +### For LynxOS 3.0.1, tested on PPC +#EXTRA_LIBS= -lXext -lSM -lICE -lnetinet -lXmu -liberty -lX11 +### For LynxOS 3.1.0, tested on PC +#EXTRA_LIBS= -lXext -lSM -lICE -lnetinet -lXmu + + +### (V) For CX/UX 6.2 (on Harris/Concurrent NightHawk 4800, 5800). Remove +### -Qtarget if only in a 5800 environment. (Kipp E. Howard) +#CFLAGS = -O -Qtarget=m88110compat +#EXTRA_LIBS = -lgen + +# The value of QUOTESED comes from auto/config.mk. +# Uncomment the next line to use the default value. +# QUOTESED = sed -e 's/[\\"]/\\&/g' -e 's/\\"/"/' -e 's/\\";$$/";/' -e 's/ */ /g' + +##################### end of system specific lines ################### }}} + +### Names of the programs and targets {{{1 +VIMTARGET = $(VIMNAME)$(EXEEXT) +EXTARGET = $(EXNAME)$(LNKEXT) +VIEWTARGET = $(VIEWNAME)$(LNKEXT) +GVIMNAME = g$(VIMNAME) +GVIMTARGET = $(GVIMNAME)$(LNKEXT) +GVIEWNAME = g$(VIEWNAME) +GVIEWTARGET = $(GVIEWNAME)$(LNKEXT) +RVIMNAME = r$(VIMNAME) +RVIMTARGET = $(RVIMNAME)$(LNKEXT) +RVIEWNAME = r$(VIEWNAME) +RVIEWTARGET = $(RVIEWNAME)$(LNKEXT) +RGVIMNAME = r$(GVIMNAME) +RGVIMTARGET = $(RGVIMNAME)$(LNKEXT) +RGVIEWNAME = r$(GVIEWNAME) +RGVIEWTARGET = $(RGVIEWNAME)$(LNKEXT) +VIMDIFFNAME = $(VIMNAME)diff +GVIMDIFFNAME = g$(VIMDIFFNAME) +VIMDIFFTARGET = $(VIMDIFFNAME)$(LNKEXT) +GVIMDIFFTARGET = $(GVIMDIFFNAME)$(LNKEXT) +EVIMNAME = e$(VIMNAME) +EVIMTARGET = $(EVIMNAME)$(LNKEXT) +EVIEWNAME = e$(VIEWNAME) +EVIEWTARGET = $(EVIEWNAME)$(LNKEXT) + +### Names of the tools that are also made {{{1 +TOOLS = xxd/xxd$(EXEEXT) + +### Installation directories. The defaults come from configure. {{{1 +# +### prefix the top directory for the data (default "/usr/local") +# +# Uncomment the next line to install Vim in your home directory. +#prefix = $(HOME) + +### exec_prefix is the top directory for the executable (default $(prefix)) +# +# Uncomment the next line to install the Vim executable in "/usr/machine/bin" +#exec_prefix = /usr/machine + +### BINDIR dir for the executable (default "$(exec_prefix)/bin") +### MANDIR dir for the manual pages (default "$(prefix)/man") +### DATADIR dir for the other files (default "$(prefix)/lib" or +# "$(prefix)/share") +# They may be different when using different architectures for the +# executable and a common directory for the other files. +# +# Uncomment the next line to install Vim in "/usr/bin" +#BINDIR = /usr/bin +# Uncomment the next line to install Vim manuals in "/usr/share/man/man1" +#MANDIR = /usr/share/man +# Uncomment the next line to install Vim help files in "/usr/share/vim" +#DATADIR = /usr/share + +### DESTDIR root of the installation tree. This is prepended to the other +# directories. This directory must exist. +#DESTDIR = ~/pkg/vim + +### Directory of the man pages +MAN1DIR = /man1 + +### Vim version (adjusted by a script) +VIMMAJOR = 9 +VIMMINOR = 0 + +### Location of Vim files (should not need to be changed, and {{{1 +### some things might not work when they are changed!) +VIMDIR = /vim +VIMRTDIR = /vim$(VIMMAJOR)$(VIMMINOR) +HELPSUBDIR = /doc +COLSUBDIR = /colors +SYNSUBDIR = /syntax +INDSUBDIR = /indent +AUTOSUBDIR = /autoload +IMPORTSUBDIR = /import +PLUGSUBDIR = /plugin +FTPLUGSUBDIR = /ftplugin +LANGSUBDIR = /lang +COMPSUBDIR = /compiler +KMAPSUBDIR = /keymap +MACROSUBDIR = /macros +PACKSUBDIR = /pack +TOOLSSUBDIR = /tools +TUTORSUBDIR = /tutor +SPELLSUBDIR = /spell +PRINTSUBDIR = /print +PODIR = po + +### VIMLOC common root of the Vim files (all versions) +### VIMRTLOC common root of the runtime Vim files (this version) +### VIMRCLOC compiled-in location for global [g]vimrc files (all versions) +### VIMRUNTIMEDIR compiled-in location for runtime files (optional) +### HELPSUBLOC location for help files +### COLSUBLOC location for colorscheme files +### SYNSUBLOC location for syntax files +### INDSUBLOC location for indent files +### AUTOSUBLOC location for standard autoload files +### IMPORTSUBLOC location for standard import files +### PLUGSUBLOC location for standard plugin files +### FTPLUGSUBLOC location for ftplugin files +### LANGSUBLOC location for language files +### COMPSUBLOC location for compiler files +### KMAPSUBLOC location for keymap files +### MACROSUBLOC location for macro files +### PACKSUBLOC location for packages +### TOOLSSUBLOC location for tools files +### TUTORSUBLOC location for tutor files +### SPELLSUBLOC location for spell files +### PRINTSUBLOC location for PostScript files (prolog, latin1, ..) +### SCRIPTLOC location for script files (menu.vim, bugreport.vim, ..) +### You can override these if you want to install them somewhere else. +### Edit feature.h for compile-time settings. +VIMLOC = $(DATADIR)$(VIMDIR) +VIMRTLOC = $(DATADIR)$(VIMDIR)$(VIMRTDIR) +VIMRCLOC = $(VIMLOC) +HELPSUBLOC = $(VIMRTLOC)$(HELPSUBDIR) +COLSUBLOC = $(VIMRTLOC)$(COLSUBDIR) +SYNSUBLOC = $(VIMRTLOC)$(SYNSUBDIR) +INDSUBLOC = $(VIMRTLOC)$(INDSUBDIR) +AUTOSUBLOC = $(VIMRTLOC)$(AUTOSUBDIR) +IMPORTSUBLOC = $(VIMRTLOC)$(IMPORTSUBDIR) +PLUGSUBLOC = $(VIMRTLOC)$(PLUGSUBDIR) +FTPLUGSUBLOC = $(VIMRTLOC)$(FTPLUGSUBDIR) +LANGSUBLOC = $(VIMRTLOC)$(LANGSUBDIR) +COMPSUBLOC = $(VIMRTLOC)$(COMPSUBDIR) +KMAPSUBLOC = $(VIMRTLOC)$(KMAPSUBDIR) +MACROSUBLOC = $(VIMRTLOC)$(MACROSUBDIR) +PACKSUBLOC = $(VIMRTLOC)$(PACKSUBDIR) +TOOLSSUBLOC = $(VIMRTLOC)$(TOOLSSUBDIR) +TUTORSUBLOC = $(VIMRTLOC)$(TUTORSUBDIR) +SPELLSUBLOC = $(VIMRTLOC)$(SPELLSUBDIR) +PRINTSUBLOC = $(VIMRTLOC)$(PRINTSUBDIR) +SCRIPTLOC = $(VIMRTLOC) + +### Only set VIMRUNTIMEDIR when VIMRTLOC is set to a different location and +### the runtime directory is not below it. +#VIMRUNTIMEDIR = $(VIMRTLOC) + +### Name of the defaults/evim/mswin file target. +VIM_DEFAULTS_FILE = $(DESTDIR)$(SCRIPTLOC)/defaults.vim +EVIM_FILE = $(DESTDIR)$(SCRIPTLOC)/evim.vim +MSWIN_FILE = $(DESTDIR)$(SCRIPTLOC)/mswin.vim + +### Name of the menu file target. +SYS_MENU_FILE = $(DESTDIR)$(SCRIPTLOC)/menu.vim +SYS_SYNMENU_FILE = $(DESTDIR)$(SCRIPTLOC)/synmenu.vim +SYS_DELMENU_FILE = $(DESTDIR)$(SCRIPTLOC)/delmenu.vim + +### Name of the bugreport file target. +SYS_BUGR_FILE = $(DESTDIR)$(SCRIPTLOC)/bugreport.vim + +### Name of the file type detection file target. +SYS_FILETYPE_FILE = $(DESTDIR)$(SCRIPTLOC)/filetype.vim + +### Name of the file type detection file target. +SYS_FTOFF_FILE = $(DESTDIR)$(SCRIPTLOC)/ftoff.vim + +### Name of the file type detection script file target. +SYS_SCRIPTS_FILE = $(DESTDIR)$(SCRIPTLOC)/scripts.vim + +### Name of the ftplugin-on file target. +SYS_FTPLUGIN_FILE = $(DESTDIR)$(SCRIPTLOC)/ftplugin.vim + +### Name of the ftplugin-off file target. +SYS_FTPLUGOF_FILE = $(DESTDIR)$(SCRIPTLOC)/ftplugof.vim + +### Name of the indent-on file target. +SYS_INDENT_FILE = $(DESTDIR)$(SCRIPTLOC)/indent.vim + +### Name of the indent-off file target. +SYS_INDOFF_FILE = $(DESTDIR)$(SCRIPTLOC)/indoff.vim + +### Name of the option window script file target. +SYS_OPTWIN_FILE = $(DESTDIR)$(SCRIPTLOC)/optwin.vim + +# Program to install the program in the target directory. Could also be "mv". +INSTALL_PROG = cp + +# Program to install the data in the target directory. Cannot be "mv"! +INSTALL_DATA = cp +INSTALL_DATA_R = cp -r + +### Program to run on installed binary. Use the second one to disable strip. +#STRIP = strip +#STRIP = /bin/true + +### Permissions for binaries {{{1 +BINMOD = 755 + +### Permissions for man page +MANMOD = 644 + +### Permissions for help files +HELPMOD = 644 + +### Permissions for Perl and shell scripts +SCRIPTMOD = 755 + +### Permission for Vim script files (menu.vim, bugreport.vim, ..) +VIMSCRIPTMOD = 644 + +### Permissions for all directories that are created +DIRMOD = 755 + +### Permissions for all other files that are created +FILEMOD = 644 + +# Where to copy the man and help files from +HELPSOURCE = ../runtime/doc + +# Where to copy the script files from (menu, bugreport) +SCRIPTSOURCE = ../runtime + +# Where to copy the colorscheme files from +COLSOURCE = ../runtime/colors + +# Where to copy the syntax files from +SYNSOURCE = ../runtime/syntax + +# Where to copy the indent files from +INDSOURCE = ../runtime/indent + +# Where to copy the standard plugin files from +AUTOSOURCE = ../runtime/autoload + +# Where to copy the standard import files from +IMPORTSOURCE = ../runtime/import + +# Where to copy the standard plugin files from +PLUGSOURCE = ../runtime/plugin + +# Where to copy the ftplugin files from +FTPLUGSOURCE = ../runtime/ftplugin + +# Where to copy the macro files from +MACROSOURCE = ../runtime/macros + +# Where to copy the package files from +PACKSOURCE = ../runtime/pack + +# Where to copy the tools files from +TOOLSSOURCE = ../runtime/tools + +# Where to copy the tutor files from +TUTORSOURCE = ../runtime/tutor + +# Where to copy the spell files from +SPELLSOURCE = ../runtime/spell + +# Where to look for language specific files +LANGSOURCE = ../runtime/lang + +# Where to look for compiler files +COMPSOURCE = ../runtime/compiler + +# Where to look for keymap files +KMAPSOURCE = ../runtime/keymap + +# Where to look for print resource files +PRINTSOURCE = ../runtime/print + +# If you are using Linux, you might want to use this to make vim the +# default vi editor, it will create a link from vi to Vim when doing +# "make install". An existing file will be overwritten! +# When not using it, some make programs can't handle an undefined $(LINKIT). +#LINKIT = ln -f -s $(DEST_BIN)/$(VIMTARGET) $(DESTDIR)/usr/bin/vi +LINKIT = @echo >/dev/null + +### +### GRAPHICAL USER INTERFACE (GUI). {{{1 +### 'configure --enable-gui' can enable one of these for you if you did set +### a corresponding CONF_OPT_GUI above and have X11. +### Override configures choice by uncommenting all the following lines. +### As they are, the GUI is disabled. Replace "NONE" with "MOTIF" +### for enabling the Motif GUI. +#GUI_SRC = $(NONE_SRC) +#GUI_OBJ = $(NONE_OBJ) +#GUI_DEFS = $(NONE_DEFS) +#GUI_IPATH = $(NONE_IPATH) +#GUI_LIBS_DIR = $(NONE_LIBS_DIR) +#GUI_LIBS1 = $(NONE_LIBS1) +#GUI_LIBS2 = $(NONE_LIBS2) +#GUI_INSTALL = $(NONE_INSTALL) +#GUI_TARGETS = $(NONE_TARGETS) +#GUI_MAN_TARGETS= $(NONE_MAN_TARGETS) +#GUI_TESTTARGET = $(NONE_TESTTARGET) +#GUI_BUNDLE = $(NONE_BUNDLE) + +# Without a GUI install the normal way. +NONE_INSTALL = install_normal + +### GTK GUI +GTK_SRC = gui.c gui_gtk.c gui_gtk_x11.c gui_gtk_f.c \ + gui_beval.c $(GRESOURCE_SRC) +GTK_OBJ = objects/gui.o objects/gui_gtk.o objects/gui_gtk_x11.o \ + objects/gui_gtk_f.o \ + objects/gui_beval.o $(GRESOURCE_OBJ) +GTK_DEFS = -DFEAT_GUI_GTK $(NARROW_PROTO) +GTK_IPATH = $(GUI_INC_LOC) +GTK_LIBS_DIR = $(GUI_LIB_LOC) +GTK_LIBS1 = +GTK_LIBS2 = $(GTK_LIBNAME) +GTK_INSTALL = install_normal install_gui_extra +GTK_TARGETS = installglinks +GTK_MAN_TARGETS = yes +GTK_TESTTARGET = gui +GTK_BUNDLE = + +### Motif GUI +MOTIF_SRC = gui.c gui_motif.c gui_x11.c gui_beval.c \ + gui_xmdlg.c gui_xmebw.c +MOTIF_OBJ = objects/gui.o objects/gui_motif.o objects/gui_x11.o \ + objects/gui_beval.o \ + objects/gui_xmdlg.o objects/gui_xmebw.o +MOTIF_DEFS = -DFEAT_GUI_MOTIF $(NARROW_PROTO) +MOTIF_IPATH = $(GUI_INC_LOC) +MOTIF_LIBS_DIR = $(GUI_LIB_LOC) +MOTIF_LIBS1 = +MOTIF_LIBS2 = $(MOTIF_LIBNAME) -lXt +MOTIF_INSTALL = install_normal install_gui_extra +MOTIF_TARGETS = installglinks +MOTIF_MAN_TARGETS = yes +MOTIF_TESTTARGET = gui +MOTIF_BUNDLE = + +### (J) Sun OpenWindows 3.2 (SunOS 4.1.x) or earlier that produce these ld +# errors: ld: Undefined symbol +# _get_wmShellWidgetClass +# _get_applicationShellWidgetClass +# then you need to get patches 100512-02 and 100573-03 from Sun. In the +# meantime, uncomment the following GUI_X_LIBS definition as a workaround: +#GUI_X_LIBS = -Bstatic -lXmu -Bdynamic -lXext +# If you also get cos, sin etc. as undefined symbols, try uncommenting this +# too: +#EXTRA_LIBS = /usr/openwin/lib/libXmu.sa -lm + +# PHOTON GUI +PHOTONGUI_SRC = gui.c gui_photon.c +PHOTONGUI_OBJ = objects/gui.o objects/gui_photon.o +PHOTONGUI_DEFS = -DFEAT_GUI_PHOTON +PHOTONGUI_IPATH = +PHOTONGUI_LIBS_DIR = +PHOTONGUI_LIBS1 = -lph -lphexlib +PHOTONGUI_LIBS2 = +PHOTONGUI_INSTALL = install_normal install_gui_extra +PHOTONGUI_TARGETS = installglinks +PHOTONGUI_MAN_TARGETS = yes +PHOTONGUI_TESTTARGET = gui +PHOTONGUI_BUNDLE = + +### Haiku GUI +HAIKUGUI_SRC = gui.c gui_haiku.cc +HAIKUGUI_OBJ = objects/gui.o objects/gui_haiku.o +HAIKUGUI_DEFS = -DFEAT_GUI_HAIKU +HAIKUGUI_IPATH = +HAIKUGUI_LIBS_DIR = +HAIKUGUI_LIBS1 = -lbe -lroot -ltracker -ltranslation -lsupc++ -lstdc++ +HAIKUGUI_LIBS2 = +HAIKUGUI_INSTALL = install_normal install_haiku_extra +HAIKUGUI_TARGETS = installglinks_haiku +HAIKUGUI_MAN_TARGETS = +HAIKUGUI_TESTTARGET = gui +HAIKUGUI_BUNDLE = + +# All GUI files +ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_gtk_x11.c gui_x11.c gui_haiku.cc +ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_gtk_x11.pro gui_x11.pro gui_w32.pro gui_photon.pro + +# }}} + +TERM_DEPS = \ + libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h \ + libvterm/src/rect.h \ + libvterm/src/utf8.h \ + libvterm/src/vterm_internal.h + +TERM_SRC = libvterm/src/*.c + +XDIFF_SRC = \ + xdiff/xdiffi.c \ + xdiff/xemit.c \ + xdiff/xprepare.c \ + xdiff/xutils.c \ + xdiff/xhistogram.c \ + xdiff/xpatience.c \ + +XDIFF_OBJS = \ + objects/xdiffi.o \ + objects/xemit.o \ + objects/xprepare.o \ + objects/xutils.o \ + objects/xhistogram.o \ + objects/xpatience.o \ + +XDIFF_INCL = \ + xdiff/xdiff.h \ + xdiff/xdiffi.h \ + xdiff/xemit.h \ + xdiff/xinclude.h \ + xdiff/xmacros.h \ + xdiff/xprepare.h \ + xdiff/xtypes.h \ + xdiff/xutils.h \ + +### Command to create dependencies based on #include "..." +### prototype headers are ignored due to -DPROTO, system +### headers #include <...> are ignored if we use the -MM option, as +### e.g. provided by gcc-cpp. +### Include FEAT_GUI to get dependency on gui.h +### Need to change "-I /" to "-isystem /" for GCC 3.x. +CPP_DEPEND = $(CC) -I$(srcdir) -M$(CPP_MM) \ + `echo "$(DEPEND_CFLAGS)" $(DEPEND_CFLAGS_FILTER)` + +# flags for cproto +# This is for cproto 3 patchlevel 8 or below +# __inline, __attribute__ and __extension__ are not recognized by cproto +# G_IMPLEMENT_INLINES is to avoid functions defined in glib/gutils.h. +#NO_ATTR = -D__inline= -D__inline__= -DG_IMPLEMENT_INLINES \ +# -D"__attribute__\\(x\\)=" -D"__asm__\\(x\\)=" \ +# -D__extension__= -D__restrict="" \ +# -D__gnuc_va_list=char -D__builtin_va_list=char +# +# This is for cproto 3 patchlevel 9 or above (currently 4.6, 4.7g) +# __inline and __attribute__ are now recognized by cproto +# __attribute() is not recognized and used in X11/Intrinsic.h +# -D"foo()=" is not supported by all compilers so do not use it +NO_ATTR = -D"__attribute\\(x\\)=" +# +# Use this for cproto 3 patchlevel 6 or below (use "cproto -V" to check): +# PROTO_FLAGS = -f4 -d -E"$(CPP)" $(NO_ATTR) +# +# Use this for cproto 3 patchlevel 7 or above (use "cproto -V" to check): +PROTO_FLAGS = -d -E"$(CPP)" $(NO_ATTR) + + +################################################ +## no changes required below this line ## +################################################ + +SHELL = /bin/sh + +# We would normally use "mkdir -p" but it doesn't work properly everywhere. +# Using AC_PROG_MKDIR_P in configure.ac has a problem with the "auto" +# directory. Always use the install-sh script, it's slower but reliable. +MKDIR_P = $(SHELL) install-sh -c -d + +.SUFFIXES: +.SUFFIXES: .c .o .pro + +VTERM_CFLAGS = -Ilibvterm/include + +PRE_DEFS = -Iproto $(DEFS) $(GUI_DEFS) $(GUI_IPATH) $(CPPFLAGS) $(EXTRA_IPATHS) +POST_DEFS = $(X_CFLAGS) $(MZSCHEME_CFLAGS) $(EXTRA_DEFS) + +ALL_CFLAGS = $(PRE_DEFS) $(CFLAGS) $(PROFILE_CFLAGS) $(SANITIZER_CFLAGS) $(LEAK_CFLAGS) $(ABORT_CFLAGS) $(POST_DEFS) + +ALL_IF_CFLAGS = $(LUA_CFLAGS) $(PERL_CFLAGS) $(PYTHON_CFLAGS) $(PYTHON3_CFLAGS) $(RUBY_CFLAGS) $(TCL_CFLAGS) +ALL_IF_CFLAGS_EXTRA = $(LUA_CFLAGS_EXTRA) $(PERL_CFLAGS_EXTRA) $(PYTHON_CFLAGS_EXTRA) $(PYTHON3_CFLAGS_EXTRA) $(RUBY_CFLAGS_EXTRA) $(TCL_CFLAGS_EXTRA) + +# Exclude $CFLAGS for osdef.sh, for Mac 10.4 some flags don't work together +# with "-E". +OSDEF_CFLAGS = $(PRE_DEFS) $(POST_DEFS) + +LINT_CFLAGS = -DLINT -I. $(PRE_DEFS) $(POST_DEFS) $(ALL_IF_CFLAGS) $(VTERM_CFLAGS) \ + -Dinline= -D__extension__= -Dalloca=alloca + +LINT_EXTRA = -D"__attribute__(x)=" + +DEPEND_CFLAGS = -DPROTO -DDEPEND -DFEAT_GUI $(LINT_CFLAGS) + +# Note: MZSCHEME_LIBS must come before LIBS, because LIBS adds -lm which is +# needed by racket. +ALL_LIB_DIRS = $(GUI_LIBS_DIR) $(X_LIBS_DIR) +ALL_LIBS = \ + $(GUI_LIBS1) \ + $(GUI_X_LIBS) \ + $(GUI_LIBS2) \ + $(X_PRE_LIBS) \ + $(X_LIBS) \ + $(X_EXTRA_LIBS) \ + $(MZSCHEME_LIBS) \ + $(LIBS) \ + $(EXTRA_LIBS) \ + $(LUA_LIBS) \ + $(PERL_LIBS) \ + $(PYTHON_LIBS) \ + $(PYTHON3_LIBS) \ + $(TCL_LIBS) \ + $(RUBY_LIBS) \ + $(PROFILE_LIBS) \ + $(SANITIZER_LIBS) \ + $(LEAK_LIBS) + +# abbreviations +DEST_BIN = $(DESTDIR)$(BINDIR) +DEST_VIM = $(DESTDIR)$(VIMLOC) +DEST_RT = $(DESTDIR)$(VIMRTLOC) +DEST_HELP = $(DESTDIR)$(HELPSUBLOC) +DEST_COL = $(DESTDIR)$(COLSUBLOC) +DEST_SYN = $(DESTDIR)$(SYNSUBLOC) +DEST_IND = $(DESTDIR)$(INDSUBLOC) +DEST_AUTO = $(DESTDIR)$(AUTOSUBLOC) +DEST_IMPORT = $(DESTDIR)$(IMPORTSUBLOC) +DEST_PLUG = $(DESTDIR)$(PLUGSUBLOC) +DEST_FTP = $(DESTDIR)$(FTPLUGSUBLOC) +DEST_LANG = $(DESTDIR)$(LANGSUBLOC) +DEST_COMP = $(DESTDIR)$(COMPSUBLOC) +DEST_KMAP = $(DESTDIR)$(KMAPSUBLOC) +DEST_MACRO = $(DESTDIR)$(MACROSUBLOC) +DEST_PACK = $(DESTDIR)$(PACKSUBLOC) +DEST_TOOLS = $(DESTDIR)$(TOOLSSUBLOC) +DEST_TUTOR = $(DESTDIR)$(TUTORSUBLOC) +DEST_SPELL = $(DESTDIR)$(SPELLSUBLOC) +DEST_SCRIPT = $(DESTDIR)$(SCRIPTLOC) +DEST_PRINT = $(DESTDIR)$(PRINTSUBLOC) +DEST_MAN_TOP = $(DESTDIR)$(MANDIR) + +# We assume that the ".../man/xx/man1/" directory is for latin1 manual pages. +# Some systems use UTF-8, but these should find the ".../man/xx.UTF-8/man1/" +# directory first. +# FreeBSD uses ".../man/xx.ISO8859-1/man1" for latin1, use that one too. +DEST_MAN = $(DEST_MAN_TOP)$(MAN1DIR) +DEST_MAN_DA = $(DEST_MAN_TOP)/da$(MAN1DIR) +DEST_MAN_DA_I = $(DEST_MAN_TOP)/da.ISO8859-1$(MAN1DIR) +DEST_MAN_DA_U = $(DEST_MAN_TOP)/da.UTF-8$(MAN1DIR) +DEST_MAN_DE = $(DEST_MAN_TOP)/de$(MAN1DIR) +DEST_MAN_DE_I = $(DEST_MAN_TOP)/de.ISO8859-1$(MAN1DIR) +DEST_MAN_DE_U = $(DEST_MAN_TOP)/de.UTF-8$(MAN1DIR) +DEST_MAN_FR = $(DEST_MAN_TOP)/fr$(MAN1DIR) +DEST_MAN_FR_I = $(DEST_MAN_TOP)/fr.ISO8859-1$(MAN1DIR) +DEST_MAN_FR_U = $(DEST_MAN_TOP)/fr.UTF-8$(MAN1DIR) +DEST_MAN_IT = $(DEST_MAN_TOP)/it$(MAN1DIR) +DEST_MAN_IT_I = $(DEST_MAN_TOP)/it.ISO8859-1$(MAN1DIR) +DEST_MAN_IT_U = $(DEST_MAN_TOP)/it.UTF-8$(MAN1DIR) +DEST_MAN_JA_U = $(DEST_MAN_TOP)/ja$(MAN1DIR) +DEST_MAN_PL = $(DEST_MAN_TOP)/pl$(MAN1DIR) +DEST_MAN_PL_I = $(DEST_MAN_TOP)/pl.ISO8859-2$(MAN1DIR) +DEST_MAN_PL_U = $(DEST_MAN_TOP)/pl.UTF-8$(MAN1DIR) +DEST_MAN_RU = $(DEST_MAN_TOP)/ru.KOI8-R$(MAN1DIR) +DEST_MAN_RU_U = $(DEST_MAN_TOP)/ru.UTF-8$(MAN1DIR) +DEST_MAN_TR = $(DEST_MAN_TOP)/tr$(MAN1DIR) +DEST_MAN_TR_I = $(DEST_MAN_TOP)/tr.ISO8859-9$(MAN1DIR) +DEST_MAN_TR_U = $(DEST_MAN_TOP)/tr.UTF-8$(MAN1DIR) + +# stuff common to all systems +include Make_all.mak + +# get the list of tests +include testdir/Make_all.mak + +# BASIC_SRC: files that are always used +# GUI_SRC: extra GUI files for current configuration +# ALL_GUI_SRC: all GUI files for Unix +# +# SRC: files used for current configuration +# ALL_SRC: source files used for make depend and make lint + +BASIC_SRC = \ + alloc.c \ + arabic.c \ + arglist.c \ + autocmd.c \ + beval.c \ + blob.c \ + blowfish.c \ + buffer.c \ + change.c \ + charset.c \ + cindent.c \ + clientserver.c \ + clipboard.c \ + cmdexpand.c \ + cmdhist.c \ + crypt.c \ + crypt_zip.c \ + debugger.c \ + dict.c \ + diff.c \ + digraph.c \ + drawline.c \ + drawscreen.c \ + edit.c \ + eval.c \ + evalbuffer.c \ + evalfunc.c \ + evalvars.c \ + evalwindow.c \ + ex_cmds.c \ + ex_cmds2.c \ + ex_docmd.c \ + ex_eval.c \ + ex_getln.c \ + fileio.c \ + filepath.c \ + findfile.c \ + float.c \ + fold.c \ + getchar.c \ + gui_xim.c \ + hardcopy.c \ + hashtab.c \ + help.c \ + highlight.c \ + if_cscope.c \ + if_xcmdsrv.c \ + indent.c \ + insexpand.c \ + json.c \ + list.c \ + locale.c \ + logfile.c \ + main.c \ + map.c \ + mark.c \ + match.c \ + mbyte.c \ + memfile.c \ + memline.c \ + menu.c \ + message.c \ + misc1.c \ + misc2.c \ + mouse.c \ + move.c \ + normal.c \ + ops.c \ + option.c \ + optionstr.c \ + os_unix.c \ + auto/pathdef.c \ + popupmenu.c \ + popupwin.c \ + profiler.c \ + pty.c \ + quickfix.c \ + regexp.c \ + register.c \ + screen.c \ + scriptfile.c \ + search.c \ + session.c \ + sha256.c \ + sign.c \ + sound.c \ + spell.c \ + spellfile.c \ + spellsuggest.c \ + strings.c \ + syntax.c \ + tag.c \ + term.c \ + terminal.c \ + testing.c \ + textformat.c \ + textobject.c \ + textprop.c \ + time.c \ + typval.c \ + ui.c \ + undo.c \ + usercmd.c \ + userfunc.c \ + version.c \ + vim9class.c \ + vim9cmds.c \ + vim9compile.c \ + vim9execute.c \ + vim9expr.c \ + vim9instr.c \ + vim9script.c \ + vim9type.c \ + viminfo.c \ + window.c \ + bufwrite.c \ + $(OS_EXTRA_SRC) + +SRC = $(BASIC_SRC) \ + $(GUI_SRC) \ + $(TERM_SRC) \ + $(XDIFF_SRC) \ + $(LUA_SRC) \ + $(MZSCHEME_SRC) \ + $(PERL_SRC) \ + $(PYTHON_SRC) $(PYTHON3_SRC) \ + $(TCL_SRC) \ + $(RUBY_SRC) + +EXTRA_SRC = if_lua.c if_mzsch.c auto/if_perl.c if_perlsfio.c \ + if_python.c if_python3.c if_tcl.c if_ruby.c \ + gui_beval.c netbeans.c job.c channel.c \ + $(GRESOURCE_SRC) + +# Unittest files +JSON_TEST_SRC = json_test.c +JSON_TEST_TARGET = json_test$(EXEEXT) +KWORD_TEST_SRC = kword_test.c +KWORD_TEST_TARGET = kword_test$(EXEEXT) +MEMFILE_TEST_SRC = memfile_test.c +MEMFILE_TEST_TARGET = memfile_test$(EXEEXT) +MESSAGE_TEST_SRC = message_test.c +MESSAGE_TEST_TARGET = message_test$(EXEEXT) + +UNITTEST_SRC = $(JSON_TEST_SRC) $(KWORD_TEST_SRC) $(MEMFILE_TEST_SRC) $(MESSAGE_TEST_SRC) +UNITTEST_TARGETS = $(JSON_TEST_TARGET) $(KWORD_TEST_TARGET) $(MEMFILE_TEST_TARGET) $(MESSAGE_TEST_TARGET) +RUN_UNITTESTS = run_json_test run_kword_test run_memfile_test run_message_test + +# All sources, also the ones that are not configured +ALL_LOCAL_SRC = $(BASIC_SRC) $(ALL_GUI_SRC) $(UNITTEST_SRC) $(EXTRA_SRC) +ALL_SRC = $(ALL_LOCAL_SRC) $(TERM_SRC) $(XDIFF_SRC) + +# Which files to check with lint. Select one of these three lines. ALL_SRC +# checks more, but may not work well for checking a GUI that wasn't configured. +# The perl sources also don't work well with lint. +LINT_SRC = $(BASIC_SRC) $(GUI_SRC) \ + $(PYTHON_SRC) $(PYTHON3_SRC) $(TCL_SRC) \ + $(NETBEANS_SRC) $(CHANNEL_SRC) $(TERM_SRC) +#LINT_SRC = $(SRC) +#LINT_SRC = $(ALL_SRC) +#LINT_SRC = $(BASIC_SRC) + +OBJ_COMMON = \ + objects/alloc.o \ + objects/arabic.o \ + objects/arglist.o \ + objects/autocmd.o \ + objects/beval.o \ + objects/buffer.o \ + objects/change.o \ + objects/blob.o \ + objects/blowfish.o \ + objects/cindent.o \ + objects/clientserver.o \ + objects/clipboard.o \ + objects/cmdexpand.o \ + objects/cmdhist.o \ + objects/crypt.o \ + objects/crypt_zip.o \ + objects/debugger.o \ + objects/dict.o \ + objects/diff.o \ + objects/digraph.o \ + objects/drawline.o \ + objects/drawscreen.o \ + objects/edit.o \ + objects/eval.o \ + objects/evalbuffer.o \ + objects/evalfunc.o \ + objects/evalvars.o \ + objects/evalwindow.o \ + objects/ex_cmds.o \ + objects/ex_cmds2.o \ + objects/ex_docmd.o \ + objects/ex_eval.o \ + objects/ex_getln.o \ + objects/fileio.o \ + objects/filepath.o \ + objects/findfile.o \ + objects/float.o \ + objects/fold.o \ + objects/getchar.o \ + objects/gui_xim.o \ + objects/hardcopy.o \ + objects/hashtab.o \ + objects/help.o \ + objects/highlight.o \ + objects/if_cscope.o \ + objects/if_xcmdsrv.o \ + objects/indent.o \ + objects/insexpand.o \ + objects/list.o \ + objects/locale.o \ + objects/logfile.o \ + objects/map.o \ + objects/mark.o \ + objects/match.o \ + objects/mbyte.o \ + objects/memline.o \ + objects/menu.o \ + objects/misc1.o \ + objects/misc2.o \ + objects/mouse.o \ + objects/move.o \ + objects/normal.o \ + objects/ops.o \ + objects/option.o \ + objects/optionstr.o \ + objects/os_unix.o \ + objects/pathdef.o \ + objects/popupmenu.o \ + objects/popupwin.o \ + objects/profiler.o \ + objects/pty.o \ + objects/quickfix.o \ + objects/regexp.o \ + objects/register.o \ + objects/screen.o \ + objects/scriptfile.o \ + objects/search.o \ + objects/session.o \ + objects/sha256.o \ + objects/sign.o \ + objects/sound.o \ + objects/spell.o \ + objects/spellfile.o \ + objects/spellsuggest.o \ + objects/strings.o \ + objects/syntax.o \ + objects/tag.o \ + objects/term.o \ + objects/terminal.o \ + objects/testing.o \ + objects/textformat.o \ + objects/textobject.o \ + objects/textprop.o \ + objects/time.o \ + objects/typval.o \ + objects/ui.o \ + objects/undo.o \ + objects/usercmd.o \ + objects/userfunc.o \ + objects/version.o \ + objects/vim9class.o \ + objects/vim9cmds.o \ + objects/vim9compile.o \ + objects/vim9execute.o \ + objects/vim9expr.o \ + objects/vim9instr.o \ + objects/vim9script.o \ + objects/vim9type.o \ + objects/viminfo.o \ + objects/window.o \ + objects/bufwrite.o \ + $(GUI_OBJ) \ + $(TERM_OBJ) \ + $(LUA_OBJ) \ + $(MZSCHEME_OBJ) \ + $(PERL_OBJ) \ + $(PYTHON_OBJ) \ + $(PYTHON3_OBJ) \ + $(TCL_OBJ) \ + $(RUBY_OBJ) \ + $(OS_EXTRA_OBJ) \ + $(NETBEANS_OBJ) \ + $(CHANNEL_OBJ) \ + $(XDIFF_OBJS_USED) + +# The files included by tests are not in OBJ_COMMON. +OBJ_MAIN = \ + objects/charset.o \ + objects/json.o \ + objects/main.o \ + objects/memfile.o \ + objects/message.o + +OBJ = $(OBJ_COMMON) $(OBJ_MAIN) + +OBJ_JSON_TEST = \ + objects/charset.o \ + objects/memfile.o \ + objects/message.o \ + objects/json_test.o + +JSON_TEST_OBJ = $(OBJ_COMMON) $(OBJ_JSON_TEST) + +OBJ_KWORD_TEST = \ + objects/json.o \ + objects/memfile.o \ + objects/message.o \ + objects/kword_test.o + +KWORD_TEST_OBJ = $(OBJ_COMMON) $(OBJ_KWORD_TEST) + +OBJ_MEMFILE_TEST = \ + objects/charset.o \ + objects/json.o \ + objects/message.o \ + objects/memfile_test.o + +MEMFILE_TEST_OBJ = $(OBJ_COMMON) $(OBJ_MEMFILE_TEST) + +OBJ_MESSAGE_TEST = \ + objects/charset.o \ + objects/json.o \ + objects/memfile.o \ + objects/message_test.o + +MESSAGE_TEST_OBJ = $(OBJ_COMMON) $(OBJ_MESSAGE_TEST) + +ALL_OBJ = $(OBJ_COMMON) \ + $(OBJ_MAIN) \ + $(OBJ_JSON_TEST) \ + $(OBJ_KWORD_TEST) \ + $(OBJ_MEMFILE_TEST) \ + $(OBJ_MESSAGE_TEST) + + +PRO_AUTO = \ + alloc.pro \ + arabic.pro \ + arglist.pro \ + autocmd.pro \ + beval.pro \ + blowfish.pro \ + buffer.pro \ + bufwrite.pro \ + change.pro \ + channel.pro \ + charset.pro \ + cindent.pro \ + clientserver.pro \ + clipboard.pro \ + cmdexpand.pro \ + cmdhist.pro \ + crypt.pro \ + crypt_zip.pro \ + debugger.pro \ + dict.pro \ + diff.pro \ + digraph.pro \ + drawline.pro \ + drawscreen.pro \ + edit.pro \ + eval.pro \ + evalbuffer.pro \ + evalfunc.pro \ + evalvars.pro \ + evalwindow.pro \ + ex_cmds.pro \ + ex_cmds2.pro \ + ex_docmd.pro \ + ex_eval.pro \ + ex_getln.pro \ + fileio.pro \ + filepath.pro \ + findfile.pro \ + float.pro \ + fold.pro \ + getchar.pro \ + gui_xim.pro \ + gui_beval.pro \ + hardcopy.pro \ + hashtab.pro \ + help.pro \ + highlight.pro \ + if_cscope.pro \ + if_lua.pro \ + if_mzsch.pro \ + if_python.pro \ + if_python3.pro \ + if_ruby.pro \ + if_xcmdsrv.pro \ + indent.pro \ + insexpand.pro \ + job.pro \ + json.pro \ + list.pro \ + locale.pro \ + logfile.pro \ + main.pro \ + map.pro \ + mark.pro \ + match.pro \ + mbyte.pro \ + memfile.pro \ + memline.pro \ + menu.pro \ + message.pro \ + misc1.pro \ + misc2.pro \ + mouse.pro \ + move.pro \ + netbeans.pro \ + normal.pro \ + ops.pro \ + option.pro \ + optionstr.pro \ + os_mac_conv.pro \ + os_unix.pro \ + popupmenu.pro \ + popupwin.pro \ + profiler.pro \ + pty.pro \ + quickfix.pro \ + regexp.pro \ + register.pro \ + screen.pro \ + scriptfile.pro \ + search.pro \ + session.pro \ + sha256.pro \ + sign.pro \ + sound.pro \ + spell.pro \ + spellfile.pro \ + spellsuggest.pro \ + strings.pro \ + syntax.pro \ + tag.pro \ + term.pro \ + terminal.pro \ + termlib.pro \ + testing.pro \ + textformat.pro \ + textobject.pro \ + textprop.pro \ + time.pro \ + typval.pro \ + ui.pro \ + undo.pro \ + usercmd.pro \ + userfunc.pro \ + version.pro \ + vim9class.pro \ + vim9cmds.pro \ + vim9compile.pro \ + vim9execute.pro \ + vim9expr.pro \ + vim9instr.pro \ + vim9script.pro \ + vim9type.pro \ + viminfo.pro \ + window.pro \ + $(ALL_GUI_PRO) \ + $(TCL_PRO) + +PRO_MANUAL = os_amiga.pro os_win32.pro \ + os_mswin.pro winclip.pro os_vms.pro $(PERL_PRO) + +# Default target is making the executable and tools +all: $(VIMTARGET) $(TOOLS) languages $(GUI_BUNDLE) + +tools: $(TOOLS) + +# Run configure with all the setting from above. +# +# Note: auto/config.h doesn't depend on configure, because running configure +# doesn't always update auto/config.h. The timestamp isn't changed if the +# file contents didn't change (to avoid recompiling everything). Including a +# dependency on auto/config.h would cause running configure each time when +# auto/config.h isn't updated. The dependency on auto/config.mk should make +# sure configure is run when it's needed. +# +# Remove the config.cache every time, once in a while it causes problems that +# are very hard to figure out. +# +config auto/config.mk: auto/configure config.mk.in config.h.in + -rm -f auto/config.cache + if test "X$(MAKECMDGOALS)" != "Xclean" \ + -a "X$(MAKECMDGOALS)" != "Xdistclean" \ + -a "X$(MAKECMDGOALS)" != "Xautoconf" \ + -a "X$(MAKECMDGOALS)" != "Xreconfig"; then \ + GUI_INC_LOC="$(GUI_INC_LOC)" GUI_LIB_LOC="$(GUI_LIB_LOC)" \ + CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \ + LDFLAGS="$(LDFLAGS)" $(CONF_SHELL) srcdir="$(srcdir)" \ + ./configure $(CONF_OPT_GUI) $(CONF_OPT_X) $(CONF_OPT_XSMP) \ + $(CONF_OPT_AUTOSERVE) $(CONF_OPT_DARWIN) $(CONF_OPT_FAIL) \ + $(CONF_OPT_PERL) $(CONF_OPT_PYTHON) $(CONF_OPT_PYTHON3) \ + $(CONF_OPT_TCL) $(CONF_OPT_RUBY) $(CONF_OPT_NLS) \ + $(CONF_OPT_CSCOPE) $(CONF_OPT_MULTIBYTE) $(CONF_OPT_INPUT) \ + $(CONF_OPT_OUTPUT) $(CONF_OPT_GPM) \ + $(CONF_OPT_FEAT) $(CONF_TERM_LIB) \ + $(CONF_OPT_COMPBY) $(CONF_OPT_ACL) $(CONF_OPT_NETBEANS) \ + $(CONF_OPT_CHANNEL) $(CONF_OPT_TERMINAL) \ + $(CONF_ARGS) $(CONF_ARGS1) $(CONF_ARGS2) $(CONF_ARGS3) \ + $(CONF_ARGS4) $(CONF_ARGS5) $(CONF_ARGS6) \ + $(CONF_OPT_MZSCHEME) $(CONF_OPT_PLTHOME) \ + $(CONF_OPT_LUA) $(CONF_OPT_LUA_PREFIX) \ + $(CONF_OPT_SYSMOUSE) $(CONF_OPT_CANBERRA) $(CONF_OPT_SODIUM); \ + fi + +# Use "make reconfig" to rerun configure without cached values. +# When config.h changes, most things will be recompiled automatically. +# Invoke $(MAKE) to run config with the empty auto/config.mk. +# Invoke $(MAKE) to build all with the filled auto/config.mk. +reconfig: scratch clean + $(MAKE) -f Makefile config + $(MAKE) -f Makefile all + +# Run autoconf to produce auto/configure. +# Note: +# - DO NOT RUN autoconf MANUALLY! It will overwrite ./configure instead of +# producing auto/configure. +# - autoconf is not run automatically, because a patch usually changes both +# configure.ac and auto/configure but can't update the timestamps. People +# who do not have (the correct version of) autoconf would run into trouble. +# +# Two tricks are required to make autoconf put its output in the "auto" dir: +# - Temporarily move the ./configure script to ./configure.save. Don't +# overwrite it, it's probably the result of an aborted autoconf. +# - Use sed to change ./config.log to auto/config.log in the configure script. +# Autoconf 2.5x (2.59 at least) produces a few more files that we need to take +# care of: +# - configure.lineno: has the line numbers replaced with $LINENO. That +# improves patches a LOT, thus use it instead (until someone says it doesn't +# work on some system). +# - autom4te.cache directory is created and not cleaned up. Delete it. +# - Uses ">config.log" instead of "./config.log". +autoconf: + if test ! -f configure.save; then mv configure configure.save; fi + $(AUTOCONF) + sed -e 's+>config.log+>auto/config.log+' -e 's+\./config.log+auto/config.log+' configure > auto/configure + chmod 755 auto/configure + mv -f configure.save configure + -rm -rf autom4te.cache + -rm -f auto/config.status auto/config.cache + +# Run vim script to generate the Ex command lookup table. +# This only needs to be run when a command name has been added or changed. +# If this fails because you don't have Vim yet, first build and install Vim +# without changes. +# This requires a "vim" executable with the +eval feature. +cmdidxs: ex_cmds.h + vim --clean -X --not-a-term -S create_cmdidxs.vim -c quit + +# Run vim script to generate the normal/visual mode command lookup table. +# This only needs to be run when a new normal/visual mode command has been +# added. +# This requires a "vim" executable with the +eval feature. +# If this fails because you don't have Vim yet: +# - change nv_cmds[] in nv_cmds.h to add the new normal/visual mode command. +# - run "make nvcmdidxs" to generate nv_cmdidxs.h +nvcmdidxs: auto/config.mk nv_cmds.h + $(CC) -I$(srcdir) $(ALL_CFLAGS) create_nvcmdidxs.c -o create_nvcmdidxs + vim --clean -X --not-a-term -S create_nvcmdidxs.vim -c quit + -rm -f create_nvcmdidxs + +# The normal command to compile a .c file to its .o file. +# Without or with ALL_CFLAGS. +CCC_NF = $(CC) -c -I$(srcdir) +CCC = $(CCC_NF) $(ALL_CFLAGS) + + +# Link the target for normal use or debugging. +# A shell script is used to try linking without unnecessary libraries. +$(VIMTARGET): auto/config.mk objects $(OBJ) version.c version.h + $(CCC) version.c -o objects/version.o + @$(BUILD_DATE_MSG) + @LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \ + -o $(VIMTARGET) $(OBJ) $(ALL_LIBS)" \ + MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \ + sh $(srcdir)/link.sh + +xxd/xxd$(EXEEXT): xxd/xxd.c + cd xxd; CC="$(CC)" CFLAGS="$(CPPFLAGS) $(CFLAGS)" LDFLAGS="$(LDFLAGS)" \ + $(MAKE) -f Makefile + +# Build the language specific files if they were unpacked. +# Generate the converted .mo files separately, it's no problem if this fails. +languages: + @if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \ + cd $(PODIR); \ + CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix); \ + fi + -@if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \ + cd $(PODIR); \ + CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix) converted; \ + fi + +# Update the *.po files for changes in the sources. Only run manually. +update-po: + cd $(PODIR); CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix) update-po + +# Generate function prototypes. This is not needed to compile vim, but if +# you want to use it, cproto is out there on the net somewhere -- Webb +# +# When generating os_amiga.pro and os_win32.pro there will be a +# few include files that can not be found, that's OK. + +proto: $(PRO_AUTO) $(PRO_MANUAL) + +# Filter out arguments that cproto doesn't support. +# Don't pass "-pthread", "-fwrapv" and similar arguments to cproto, it sees +# them as a list of individual flags. +# The -E"gcc -E" argument must be separate to avoid problems with shell +# quoting. +# Strip -O2, it may cause cproto to write stderr to the file "2". +CPROTO = cproto $(PROTO_FLAGS) -DPROTO \ + `echo '$(LINT_CFLAGS)' | sed -e 's/ -[a-z-]\+//g' -e 's/ -O[^ ]\+//g'` + +### Would be nice if this would work for "normal" make. +### Currently it only works for (Free)BSD make. +#$(PRO_AUTO): $$(*F).c +# $(CPROTO) -DFEAT_GUI $(*F).c > $@ + +# Always define FEAT_GUI. This may generate a few warnings if it's also +# defined in auto/config.h, you can ignore that. +.c.pro: + $(CPROTO) -DFEAT_GUI $< > proto/$@ + echo "/* vim: set ft=c : */" >> proto/$@ + +os_amiga.pro: os_amiga.c + $(CPROTO) -DAMIGA -UHAVE_CONFIG_H -DBPTR=char* $< > proto/$@ + echo "/* vim: set ft=c : */" >> proto/$@ + +os_win32.pro: os_win32.c + $(CPROTO) -DWIN32 -UHAVE_CONFIG_H $< > proto/$@ + echo "/* vim: set ft=c : */" >> proto/$@ + +os_mswin.pro: os_mswin.c + $(CPROTO) -DWIN32 -UHAVE_CONFIG_H $< > proto/$@ + echo "/* vim: set ft=c : */" >> proto/$@ + +winclip.pro: winclip.c + $(CPROTO) -DWIN32 -UHAVE_CONFIG_H $< > proto/$@ + echo "/* vim: set ft=c : */" >> proto/$@ + +os_vms.pro: os_vms.c +# must use os_vms_conf.h for auto/config.h + mv auto/config.h auto/config.h.save + cp os_vms_conf.h auto/config.h + $(CPROTO) -DVMS -UFEAT_GUI_MOTIF -UFEAT_GUI_GTK $< > proto/$@ + echo "/* vim: set ft=c : */" >> proto/$@ + rm auto/config.h + mv auto/config.h.save auto/config.h + +# if_perl.pro is special: Use the generated if_perl.c for input and remove +# prototypes for local functions. +if_perl.pro: auto/if_perl.c + $(CPROTO) -DFEAT_GUI auto/if_perl.c | sed "/_VI/d" > proto/$@ + +gui_gtk_gresources.pro: auto/gui_gtk_gresources.c + $(CPROTO) -DFEAT_GUI $< > proto/$@ + echo "/* vim: set ft=c : */" >> proto/$@ + +notags: + -rm -f tags + +# Note: tags is made for the currently configured version. +# You can ignore error messages for missing files. +tags TAGS: notags + $(TAGPRG) $(TAGS_FILES) + +# Make a highlight file for types. Requires Exuberant ctags and awk +types: types.vim +types.vim: $(TAGS_FILES) + ctags --c-kinds=gstu -o- $(TAGS_FILES) |\ + awk 'BEGIN{printf("syntax keyword Type\t")}\ + {printf("%s ", $$1)}END{print ""}' > $@ + echo "syn keyword Constant OK FAIL TRUE FALSE MAYBE" >> $@ + +# TESTING +# +# Execute the test scripts and the unittests. +# Do the scripttests first, so that the summary shows last. +test check: unittests $(TERM_TEST) scripttests + +# Execute the test scripts. Run these after compiling Vim, before installing. +# This doesn't depend on $(VIMTARGET), because that won't work when configure +# wasn't run yet. Restart make to build it instead. +# +# This will produce a lot of garbage on your screen, including a few error +# messages. Don't worry about that. +# If everything is alright, the final message will be "ALL DONE". If not you +# get "TEST FAILURE". +# +scripttests: + $(MAKE) -f Makefile $(VIMTARGET) + if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \ + cd $(PODIR); $(MAKE) -f Makefile check VIM=../$(VIMTARGET); \ + fi + -if test $(VIMTARGET) != vim -a ! -r vim; then \ + ln -s $(VIMTARGET) vim; \ + fi + cd testdir; $(MAKE) -f Makefile $(GUI_TESTTARGET) VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) + +# Run the tests with the GUI. Assumes vim/gvim was already built +testgui: + cd testdir; $(MAKE) -f Makefile $(GUI_TESTTARGET) VIMPROG=../$(VIMTARGET) GUI_FLAG=-g $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) + +testtiny: + cd testdir; $(MAKE) -f Makefile tiny VIMPROG=../$(VIMTARGET) SCRIPTSOURCE=../$(SCRIPTSOURCE) + +# Run benchmarks. +benchmark: + cd testdir; \ + $(MAKE) -f Makefile benchmarkclean; \ + $(MAKE) -f Makefile benchmark VIMPROG=../$(VIMTARGET) SCRIPTSOURCE=../$(SCRIPTSOURCE) + +unittesttargets: + $(MAKE) -f Makefile $(UNITTEST_TARGETS) + +# Swap these lines to run individual tests with gvim instead of vim. +VIMTESTTARGET = $(VIMTARGET) +# VIMTESTTARGET = $(GVIMTARGET) + +# Execute the unittests one by one. +unittest unittests: $(RUN_UNITTESTS) + +run_json_test: $(JSON_TEST_TARGET) + $(VALGRIND) ./$(JSON_TEST_TARGET) || exit 1; echo $* passed; + +run_kword_test: $(KWORD_TEST_TARGET) + $(VALGRIND) ./$(KWORD_TEST_TARGET) || exit 1; echo $* passed; + +run_memfile_test: $(MEMFILE_TEST_TARGET) + $(VALGRIND) ./$(MEMFILE_TEST_TARGET) || exit 1; echo $* passed; + +run_message_test: $(MESSAGE_TEST_TARGET) + $(VALGRIND) ./$(MESSAGE_TEST_TARGET) || exit 1; echo $* passed; + +# Run the libvterm tests. +# This works only on GNU make, not on BSD make. +# Libtool requires "gcc". +test_libvterm: + @if $(MAKE) --version 2>/dev/null | grep -qs "GNU Make"; then \ + if test -x "/usr/bin/gcc"; then \ + cd libvterm; $(MAKE) -f Makefile test CC="$(CC)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)"; \ + fi \ + fi + +# Run individual OLD style test. +# These do not depend on the executable, compile it when needed. +$(SCRIPTS_TINY): + cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) + +# Run individual NEW style test. +# These do not depend on the executable, compile it when needed. +# Set $TEST_FILTER to select what test function to invoke, e.g.: +# export TEST_FILTER=Test_terminal_wipe_buffer +# A partial match also works: +# export TEST_FILTER=wipe_buffer +$(NEW_TESTS) test_vim9: + cd testdir; $(MAKE) $@ VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) + +newtests: + cd testdir; rm -f $@.res test.log messages; $(MAKE) -f Makefile newtestssilent VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) + @if test -f testdir/test.log; then \ + cat testdir/test.log; \ + fi + cat testdir/messages + +testclean: + cd testdir; $(MAKE) -f Makefile clean + if test -d $(PODIR); then \ + cd $(PODIR); $(MAKE) checkclean; \ + fi + +# Unittests +# It's build just like Vim to satisfy all dependencies. +$(JSON_TEST_TARGET): auto/config.mk objects $(JSON_TEST_OBJ) + $(CCC) version.c -o objects/version.o + @LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \ + -o $(JSON_TEST_TARGET) $(JSON_TEST_OBJ) $(ALL_LIBS)" \ + MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \ + sh $(srcdir)/link.sh + +$(KWORD_TEST_TARGET): auto/config.mk objects $(KWORD_TEST_OBJ) + $(CCC) version.c -o objects/version.o + @LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \ + -o $(KWORD_TEST_TARGET) $(KWORD_TEST_OBJ) $(ALL_LIBS)" \ + MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \ + sh $(srcdir)/link.sh + +$(MEMFILE_TEST_TARGET): auto/config.mk objects $(MEMFILE_TEST_OBJ) + $(CCC) version.c -o objects/version.o + @LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \ + -o $(MEMFILE_TEST_TARGET) $(MEMFILE_TEST_OBJ) $(ALL_LIBS)" \ + MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \ + sh $(srcdir)/link.sh + +$(MESSAGE_TEST_TARGET): auto/config.mk objects $(MESSAGE_TEST_OBJ) + $(CCC) version.c -o objects/version.o + @LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \ + -o $(MESSAGE_TEST_TARGET) $(MESSAGE_TEST_OBJ) $(ALL_LIBS)" \ + MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \ + sh $(srcdir)/link.sh + +# install targets + +install: $(GUI_INSTALL) + +install_normal: installvim installtools $(INSTALL_LANGS) install-icons + +install_gui_extra: installgtutorbin + +installvim: installvimbin installtutorbin \ + installruntime installlinks installmanlinks + +# +# Avoid overwriting an existing executable, somebody might be running it and +# overwriting it could cause it to crash. Deleting it is OK, it won't be +# really deleted until all running processes for it have exited. It is +# renamed first, in case the deleting doesn't work. +# +# If you want to keep an older version, rename it before running "make +# install". +# +installvimbin: $(VIMTARGET) $(DESTDIR)$(exec_prefix) $(DEST_BIN) + -if test -f $(DEST_BIN)/$(VIMTARGET); then \ + mv -f $(DEST_BIN)/$(VIMTARGET) $(DEST_BIN)/$(VIMNAME).rm; \ + rm -f $(DEST_BIN)/$(VIMNAME).rm; \ + fi + $(INSTALL_PROG) $(VIMTARGET) $(DEST_BIN) + $(STRIP) $(DEST_BIN)/$(VIMTARGET) + chmod $(BINMOD) $(DEST_BIN)/$(VIMTARGET) +# may create a link to the new executable from /usr/bin/vi + -$(LINKIT) + +# Long list of arguments for the shell script that installs the manual pages +# for one language. +INSTALLMANARGS = $(VIMLOC) $(SCRIPTLOC) $(VIMRCLOC) $(HELPSOURCE) $(MANMOD) \ + $(VIMNAME) $(VIMDIFFNAME) $(EVIMNAME) + +# Install most of the runtime files +installruntime: installrtbase installmacros installpack installtutor installspell + +# Install the help files; first adjust the contents for the final location. +# Also install most of the other runtime files. +installrtbase: $(HELPSOURCE)/vim.1 $(DEST_VIM) $(DEST_RT) \ + $(DEST_HELP) $(DEST_PRINT) $(DEST_COL) \ + $(DEST_SYN) $(DEST_SYN)/shared $(DEST_IND) \ + $(DEST_FTP) $(DEST_AUTO) $(DEST_AUTO)/dist $(DEST_AUTO)/xml \ + $(DEST_IMPORT) $(DEST_IMPORT)/dist \ + $(DEST_PLUG) $(DEST_TUTOR) $(DEST_SPELL) $(DEST_COMP) + -$(SHELL) ./installman.sh install $(DEST_MAN) "" $(INSTALLMANARGS) +# Generate the help tags with ":helptags" to handle all languages. +# Move the distributed tags file aside and restore it, to avoid it being +# different from the repository. + cd $(HELPSOURCE); if test -z "$(CROSS_COMPILING)" -a -f tags; then \ + mv -f tags tags.dist; fi + @echo generating help tags + -@cd $(HELPSOURCE); if test -z "$(CROSS_COMPILING)"; then \ + $(MAKE) VIMEXE=$(DEST_BIN)/$(VIMTARGET) vimtags; fi + cd $(HELPSOURCE); \ + files=`ls *.txt tags`; \ + files="$$files `ls *.??x tags-?? 2>/dev/null || true`"; \ + $(INSTALL_DATA) $$files $(DEST_HELP); \ + cd $(DEST_HELP); \ + chmod $(HELPMOD) $$files + $(INSTALL_DATA) $(HELPSOURCE)/*.pl $(DEST_HELP) + chmod $(SCRIPTMOD) $(DEST_HELP)/*.pl + cd $(HELPSOURCE); if test -f tags.dist; then mv -f tags.dist tags; fi +# install the menu files + $(INSTALL_DATA) $(SCRIPTSOURCE)/menu.vim $(SYS_MENU_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_MENU_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/synmenu.vim $(SYS_SYNMENU_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_SYNMENU_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/delmenu.vim $(SYS_DELMENU_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_DELMENU_FILE) +# install the defaults/evim/mswin file + $(INSTALL_DATA) $(SCRIPTSOURCE)/defaults.vim $(VIM_DEFAULTS_FILE) + chmod $(VIMSCRIPTMOD) $(VIM_DEFAULTS_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/evim.vim $(EVIM_FILE) + chmod $(VIMSCRIPTMOD) $(EVIM_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/mswin.vim $(MSWIN_FILE) + chmod $(VIMSCRIPTMOD) $(MSWIN_FILE) +# install the bugreport file + $(INSTALL_DATA) $(SCRIPTSOURCE)/bugreport.vim $(SYS_BUGR_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_BUGR_FILE) +# install the example vimrc files + $(INSTALL_DATA) $(SCRIPTSOURCE)/vimrc_example.vim $(DEST_SCRIPT) + chmod $(VIMSCRIPTMOD) $(DEST_SCRIPT)/vimrc_example.vim + $(INSTALL_DATA) $(SCRIPTSOURCE)/gvimrc_example.vim $(DEST_SCRIPT) + chmod $(VIMSCRIPTMOD) $(DEST_SCRIPT)/gvimrc_example.vim +# install the file type detection files + $(INSTALL_DATA) $(SCRIPTSOURCE)/filetype.vim $(SYS_FILETYPE_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_FILETYPE_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/ftoff.vim $(SYS_FTOFF_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_FTOFF_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/scripts.vim $(SYS_SCRIPTS_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_SCRIPTS_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/ftplugin.vim $(SYS_FTPLUGIN_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_FTPLUGIN_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/ftplugof.vim $(SYS_FTPLUGOF_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_FTPLUGOF_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/indent.vim $(SYS_INDENT_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_INDENT_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/indoff.vim $(SYS_INDOFF_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_INDOFF_FILE) + $(INSTALL_DATA) $(SCRIPTSOURCE)/optwin.vim $(SYS_OPTWIN_FILE) + chmod $(VIMSCRIPTMOD) $(SYS_OPTWIN_FILE) +# install the print resource files + cd $(PRINTSOURCE); $(INSTALL_DATA) *.ps $(DEST_PRINT) + cd $(DEST_PRINT); chmod $(FILEMOD) *.ps +# install the colorscheme files + cd $(COLSOURCE); $(INSTALL_DATA_R) *.vim lists tools README.txt $(DEST_COL) + cd $(DEST_COL); chmod $(DIRMOD) lists tools + cd $(DEST_COL); chmod $(HELPMOD) *.vim README.txt lists/*.vim tools/*.vim +# install the syntax files + cd $(SYNSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_SYN) + cd $(DEST_SYN); chmod $(HELPMOD) *.vim README.txt + cd $(SYNSOURCE)/shared; $(INSTALL_DATA) *.vim README.txt $(DEST_SYN)/shared + cd $(DEST_SYN)/shared; chmod $(HELPMOD) *.vim README.txt +# install the indent files + cd $(INDSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_IND) + cd $(DEST_IND); chmod $(HELPMOD) *.vim README.txt +# install the standard autoload files + cd $(AUTOSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_AUTO) + cd $(DEST_AUTO); chmod $(HELPMOD) *.vim README.txt + cd $(AUTOSOURCE)/dist; $(INSTALL_DATA) *.vim $(DEST_AUTO)/dist + cd $(DEST_AUTO)/dist; chmod $(HELPMOD) *.vim + cd $(AUTOSOURCE)/xml; $(INSTALL_DATA) *.vim $(DEST_AUTO)/xml + cd $(DEST_AUTO)/xml; chmod $(HELPMOD) *.vim +# install the standard import files + cd $(IMPORTSOURCE)/dist; $(INSTALL_DATA) *.vim $(DEST_IMPORT)/dist + cd $(DEST_IMPORT)/dist; chmod $(HELPMOD) *.vim +# install the standard plugin files + cd $(PLUGSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_PLUG) + cd $(DEST_PLUG); chmod $(HELPMOD) *.vim README.txt +# install the ftplugin files + cd $(FTPLUGSOURCE); $(INSTALL_DATA) *.vim README.txt logtalk.dict $(DEST_FTP) + cd $(DEST_FTP); chmod $(HELPMOD) *.vim README.txt logtalk.dict +# install the compiler files + cd $(COMPSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_COMP) + cd $(DEST_COMP); chmod $(HELPMOD) *.vim README.txt + +installmacros: $(DEST_VIM) $(DEST_RT) $(DEST_MACRO) + $(INSTALL_DATA_R) $(MACROSOURCE)/* $(DEST_MACRO) + chmod $(DIRMOD) `find $(DEST_MACRO) -type d -print` + chmod $(FILEMOD) `find $(DEST_MACRO) -type f -print` + chmod $(SCRIPTMOD) $(DEST_MACRO)/less.sh +# When using CVS some CVS directories might have been copied. +# Also delete AAPDIR and *.info files. + cvs=`find $(DEST_MACRO) \( -name CVS -o -name AAPDIR -o -name "*.info" \) -print`; \ + if test -n "$$cvs"; then \ + rm -rf $$cvs; \ + fi + +installpack: $(DEST_VIM) $(DEST_RT) $(DEST_PACK) + $(INSTALL_DATA_R) $(PACKSOURCE)/* $(DEST_PACK) + chmod $(DIRMOD) `find $(DEST_PACK) -type d -print` + chmod $(FILEMOD) `find $(DEST_PACK) -type f -print` + +# install the tutor files +installtutorbin: $(DEST_BIN) + $(INSTALL_DATA) vimtutor $(DEST_BIN)/$(VIMNAME)tutor + chmod $(SCRIPTMOD) $(DEST_BIN)/$(VIMNAME)tutor + +installgtutorbin: $(DEST_BIN) + $(INSTALL_DATA) gvimtutor $(DEST_BIN)/$(GVIMNAME)tutor + chmod $(SCRIPTMOD) $(DEST_BIN)/$(GVIMNAME)tutor + +installtutor: $(DEST_RT) $(DEST_TUTOR) + -$(INSTALL_DATA) $(TUTORSOURCE)/README* $(TUTORSOURCE)/tutor* $(DEST_TUTOR) + -rm -f $(DEST_TUTOR)/*.info + chmod $(HELPMOD) $(DEST_TUTOR)/* + +# Install the spell files, if they exist. This assumes at least the English +# spell file is there. +installspell: $(DEST_VIM) $(DEST_RT) $(DEST_SPELL) + if test -f $(SPELLSOURCE)/en.latin1.spl; then \ + $(INSTALL_DATA) $(SPELLSOURCE)/*.spl $(SPELLSOURCE)/*.sug $(SPELLSOURCE)/*.vim $(DEST_SPELL); \ + chmod $(HELPMOD) $(DEST_SPELL)/*.spl $(DEST_SPELL)/*.sug $(DEST_SPELL)/*.vim; \ + fi + +# install helper program xxd +installtools: $(TOOLS) $(DESTDIR)$(exec_prefix) $(DEST_BIN) \ + $(TOOLSSOURCE) $(DEST_VIM) $(DEST_RT) $(DEST_TOOLS) \ + $(INSTALL_TOOL_LANGS) + if test -f $(DEST_BIN)/xxd$(EXEEXT); then \ + mv -f $(DEST_BIN)/xxd$(EXEEXT) $(DEST_BIN)/xxd.rm; \ + rm -f $(DEST_BIN)/xxd.rm; \ + fi + $(INSTALL_PROG) xxd/xxd$(EXEEXT) $(DEST_BIN) + $(STRIP) $(DEST_BIN)/xxd$(EXEEXT) + chmod $(BINMOD) $(DEST_BIN)/xxd$(EXEEXT) + -$(SHELL) ./installman.sh xxd $(DEST_MAN) "" $(INSTALLMANARGS) + +# install the runtime tools + $(INSTALL_DATA_R) $(TOOLSSOURCE)/* $(DEST_TOOLS) +# When using CVS some CVS directories might have been copied. + cvs=`find $(DEST_TOOLS) \( -name CVS -o -name AAPDIR \) -print`; \ + if test -n "$$cvs"; then \ + rm -rf $$cvs; \ + fi + -chmod $(FILEMOD) $(DEST_TOOLS)/* +# replace the path in some tools + perlpath=`./which.sh perl` && sed -e "s+/usr/bin/perl+$$perlpath+" $(TOOLSSOURCE)/efm_perl.pl >$(DEST_TOOLS)/efm_perl.pl + awkpath=`./which.sh nawk` && sed -e "s+/usr/bin/nawk+$$awkpath+" $(TOOLSSOURCE)/mve.awk >$(DEST_TOOLS)/mve.awk; if test -z "$$awkpath"; then \ + awkpath=`./which.sh gawk` && sed -e "s+/usr/bin/nawk+$$awkpath+" $(TOOLSSOURCE)/mve.awk >$(DEST_TOOLS)/mve.awk; if test -z "$$awkpath"; then \ + awkpath=`./which.sh awk` && sed -e "s+/usr/bin/nawk+$$awkpath+" $(TOOLSSOURCE)/mve.awk >$(DEST_TOOLS)/mve.awk; fi; fi + -chmod $(SCRIPTMOD) `grep -l "^#!" $(DEST_TOOLS)/*` + +# install the language specific files for tools, if they were unpacked +install-tool-languages: + -$(SHELL) ./installman.sh xxd $(DEST_MAN_DA) "-da" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_DA_I) "-da" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_DA_U) "-da.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_DE) "-de" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_DE_I) "-de" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_DE_U) "-de.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_FR) "-fr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_FR_I) "-fr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_FR_U) "-fr.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_IT) "-it" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_IT_I) "-it" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_IT_U) "-it.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_JA_U) "-ja.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_PL) "-pl" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_PL_I) "-pl" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_PL_U) "-pl.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_RU) "-ru" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_RU_U) "-ru.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_TR) "-tr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_TR_I) "-tr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_TR_U) "-tr.UTF-8" $(INSTALLMANARGS) + + +# install the language specific files, if they were unpacked +install-languages: languages $(DEST_LANG) $(DEST_KMAP) + -$(SHELL) ./installman.sh install $(DEST_MAN_DA) "-da" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_DA_I) "-da" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_DA_U) "-da.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_DE) "-de" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_DE_I) "-de" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_DE_U) "-de.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_FR) "-fr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_FR_I) "-fr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_FR_U) "-fr.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_IT) "-it" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_IT_I) "-it" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_IT_U) "-it.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_JA_U) "-ja.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_PL) "-pl" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_PL_I) "-pl" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_PL_U) "-pl.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_RU) "-ru" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_RU_U) "-ru.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_TR) "-tr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_TR_I) "-tr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_TR_U) "-tr.UTF-8" $(INSTALLMANARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DA) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DA_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DA_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DE) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DE_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DE_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_IT) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_IT_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_IT_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_JA_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_PL) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_PL_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_PL_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_RU) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_RU_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_TR) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_TR_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_TR_U) $(INSTALLMLARGS) + if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \ + cd $(PODIR); $(MAKE) prefix=$(DESTDIR)$(prefix) LOCALEDIR=$(DEST_LANG) \ + INSTALL_DATA=$(INSTALL_DATA) FILEMOD=$(FILEMOD) install; \ + fi + if test -d $(LANGSOURCE); then \ + $(INSTALL_DATA) $(LANGSOURCE)/README.txt $(LANGSOURCE)/*.vim $(DEST_LANG); \ + chmod $(FILEMOD) $(DEST_LANG)/README.txt $(DEST_LANG)/*.vim; \ + fi + if test -d $(KMAPSOURCE); then \ + $(INSTALL_DATA) $(KMAPSOURCE)/README.txt $(KMAPSOURCE)/*.vim $(DEST_KMAP); \ + chmod $(FILEMOD) $(DEST_KMAP)/README.txt $(DEST_KMAP)/*.vim; \ + fi + +# Install the icons for KDE, if the directory exists and the icon doesn't. +# Always when $(DESTDIR) is not empty. +ICON48PATH = $(DESTDIR)$(DATADIR)/icons/hicolor/48x48/apps +ICON32PATH = $(DESTDIR)$(DATADIR)/icons/locolor/32x32/apps +ICON16PATH = $(DESTDIR)$(DATADIR)/icons/locolor/16x16/apps +ICONTHEMEPATH = $(DATADIR)/icons/hicolor +DESKTOPPATH = $(DESTDIR)$(DATADIR)/applications +KDEPATH = $(HOME)/.kde/share/icons +install-icons: + if test -n "$(DESTDIR)"; then \ + $(MKDIR_P) $(ICON48PATH) $(ICON32PATH) \ + $(ICON16PATH) $(DESKTOPPATH); \ + fi + + if test -d $(ICON48PATH) -a -w $(ICON48PATH) \ + -a ! -f $(ICON48PATH)/gvim.png; then \ + $(INSTALL_DATA) $(SCRIPTSOURCE)/vim48x48.png $(ICON48PATH)/gvim.png; \ + if test -z "$(DESTDIR)" -a -x "$(GTK_UPDATE_ICON_CACHE)" \ + -a -w $(ICONTHEMEPATH) \ + -a -f $(ICONTHEMEPATH)/index.theme; then \ + $(GTK_UPDATE_ICON_CACHE) -q $(ICONTHEMEPATH); \ + fi \ + fi + if test -d $(ICON32PATH) -a -w $(ICON32PATH) \ + -a ! -f $(ICON32PATH)/gvim.png; then \ + $(INSTALL_DATA) $(SCRIPTSOURCE)/vim32x32.png $(ICON32PATH)/gvim.png; \ + fi + if test -d $(ICON16PATH) -a -w $(ICON16PATH) \ + -a ! -f $(ICON16PATH)/gvim.png; then \ + $(INSTALL_DATA) $(SCRIPTSOURCE)/vim16x16.png $(ICON16PATH)/gvim.png; \ + fi + if test -d $(DESKTOPPATH) -a -w $(DESKTOPPATH); then \ + if test -f po/vim.desktop -a -f po/gvim.desktop; then \ + $(INSTALL_DATA) po/vim.desktop po/gvim.desktop \ + $(DESKTOPPATH); \ + else \ + $(INSTALL_DATA) $(SCRIPTSOURCE)/vim.desktop \ + $(SCRIPTSOURCE)/gvim.desktop \ + $(DESKTOPPATH); \ + fi; \ + if test -z "$(DESTDIR)" -a -x "$(UPDATE_DESKTOP_DATABASE)"; then \ + $(UPDATE_DESKTOP_DATABASE) -q $(DESKTOPPATH); \ + fi \ + fi + +$(HELPSOURCE)/vim.1 $(MACROSOURCE) $(TOOLSSOURCE): + @echo Runtime files not found. + @echo You need to unpack the runtime archive before running "make install". + test -f error + +$(DESTDIR)$(exec_prefix) $(DEST_BIN) \ + $(DEST_VIM) $(DEST_RT) $(DEST_HELP) \ + $(DEST_PRINT) $(DEST_COL) $(DEST_SYN) $(DEST_SYN)/shared \ + $(DEST_IND) $(DEST_FTP) \ + $(DEST_LANG) $(DEST_KMAP) $(DEST_COMP) $(DEST_MACRO) \ + $(DEST_PACK) $(DEST_TOOLS) $(DEST_TUTOR) $(DEST_SPELL) \ + $(DEST_AUTO) $(DEST_AUTO)/dist $(DEST_AUTO)/xml \ + $(DEST_IMPORT) $(DEST_IMPORT)/dist $(DEST_PLUG): + $(MKDIR_P) $@ + -chmod $(DIRMOD) $@ + +# create links from various names to vim. This is only done when the links +# (or executables with the same name) don't exist yet. +installlinks: $(GUI_TARGETS) \ + $(DEST_BIN)/$(EXTARGET) \ + $(DEST_BIN)/$(VIEWTARGET) \ + $(DEST_BIN)/$(RVIMTARGET) \ + $(DEST_BIN)/$(RVIEWTARGET) \ + $(INSTALLVIMDIFF) + +installglinks: $(DEST_BIN)/$(GVIMTARGET) \ + $(DEST_BIN)/$(GVIEWTARGET) \ + $(DEST_BIN)/$(RGVIMTARGET) \ + $(DEST_BIN)/$(RGVIEWTARGET) \ + $(DEST_BIN)/$(EVIMTARGET) \ + $(DEST_BIN)/$(EVIEWTARGET) \ + $(INSTALLGVIMDIFF) + +installvimdiff: $(DEST_BIN)/$(VIMDIFFTARGET) +installgvimdiff: $(DEST_BIN)/$(GVIMDIFFTARGET) + +$(DEST_BIN)/$(EXTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(EXTARGET) + +$(DEST_BIN)/$(VIEWTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(VIEWTARGET) + +$(DEST_BIN)/$(GVIMTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(GVIMTARGET) + +$(DEST_BIN)/$(GVIEWTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(GVIEWTARGET) + +$(DEST_BIN)/$(RVIMTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(RVIMTARGET) + +$(DEST_BIN)/$(RVIEWTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(RVIEWTARGET) + +$(DEST_BIN)/$(RGVIMTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(RGVIMTARGET) + +$(DEST_BIN)/$(RGVIEWTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(RGVIEWTARGET) + +$(DEST_BIN)/$(VIMDIFFTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(VIMDIFFTARGET) + +$(DEST_BIN)/$(GVIMDIFFTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(GVIMDIFFTARGET) + +$(DEST_BIN)/$(EVIMTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(EVIMTARGET) + +$(DEST_BIN)/$(EVIEWTARGET): + cd $(DEST_BIN); ln -s $(VIMTARGET) $(EVIEWTARGET) + +# Create links for the manual pages with various names to vim. This is only +# done when the links (or manpages with the same name) don't exist yet. + +INSTALLMLARGS = $(VIMNAME) $(VIMDIFFNAME) $(EVIMNAME) \ + $(EXNAME) $(VIEWNAME) $(RVIMNAME) $(RVIEWNAME) \ + $(GVIMNAME) $(GVIEWNAME) $(RGVIMNAME) $(RGVIEWNAME) \ + $(GVIMDIFFNAME) $(EVIEWNAME) + +installmanlinks: + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN) $(INSTALLMLARGS) + +uninstall: uninstall_runtime + -rm -f $(DEST_BIN)/$(VIMTARGET) + -rm -f $(DEST_BIN)/vimtutor + -rm -f $(DEST_BIN)/gvimtutor + -rm -f $(DEST_BIN)/$(EXTARGET) $(DEST_BIN)/$(VIEWTARGET) + -rm -f $(DEST_BIN)/$(GVIMTARGET) $(DEST_BIN)/$(GVIEWTARGET) + -rm -f $(DEST_BIN)/$(RVIMTARGET) $(DEST_BIN)/$(RVIEWTARGET) + -rm -f $(DEST_BIN)/$(RGVIMTARGET) $(DEST_BIN)/$(RGVIEWTARGET) + -rm -f $(DEST_BIN)/$(VIMDIFFTARGET) $(DEST_BIN)/$(GVIMDIFFTARGET) + -rm -f $(DEST_BIN)/$(EVIMTARGET) $(DEST_BIN)/$(EVIEWTARGET) + -rm -f $(DEST_BIN)/xxd$(EXEEXT) + +# Note: the "rmdir" will fail if any files were added after "make install" +uninstall_runtime: + -$(SHELL) ./installman.sh uninstall $(DEST_MAN) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DA) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DA_I) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DA_U) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DE) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DE_I) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DE_U) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_FR) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_FR_I) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_FR_U) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_IT) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_IT_I) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_IT_U) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_JA_U) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_PL) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_PL_I) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_PL_U) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_RU) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_RU_U) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_TR) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_TR_I) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_TR_U) "" $(INSTALLMANARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DA) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DA_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DA_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DE) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DE_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_DE_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_IT) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_IT_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_IT_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_JA_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_PL) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_PL_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_PL_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_RU) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_RU_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_TR) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_TR_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_TR_U) $(INSTALLMLARGS) + -rm -f $(DEST_MAN)/xxd.1 + -rm -f $(DEST_MAN_DA)/xxd.1 $(DEST_MAN_DA_I)/xxd.1 $(DEST_MAN_DA_U)/xxd.1 + -rm -f $(DEST_MAN_DE)/xxd.1 $(DEST_MAN_DE_I)/xxd.1 $(DEST_MAN_DE_U)/xxd.1 + -rm -f $(DEST_MAN_FR)/xxd.1 $(DEST_MAN_FR_I)/xxd.1 $(DEST_MAN_FR_U)/xxd.1 + -rm -f $(DEST_MAN_IT)/xxd.1 $(DEST_MAN_IT_I)/xxd.1 $(DEST_MAN_IT_U)/xxd.1 + -rm -f $(DEST_MAN_JA_U)/xxd.1 + -rm -f $(DEST_MAN_PL)/xxd.1 $(DEST_MAN_PL_I)/xxd.1 $(DEST_MAN_PL_U)/xxd.1 + -rm -f $(DEST_MAN_RU)/xxd.1 $(DEST_MAN_RU_U)/xxd.1 + -rm -f $(DEST_HELP)/*.txt $(DEST_HELP)/tags $(DEST_HELP)/*.pl + -rm -f $(DEST_HELP)/*.??x $(DEST_HELP)/tags-?? + -rm -f $(SYS_MENU_FILE) $(SYS_SYNMENU_FILE) $(SYS_DELMENU_FILE) + -rm -f $(SYS_BUGR_FILE) $(VIM_DEFAULTS_FILE) $(EVIM_FILE) $(MSWIN_FILE) + -rm -f $(DEST_SCRIPT)/gvimrc_example.vim $(DEST_SCRIPT)/vimrc_example.vim + -rm -f $(SYS_FILETYPE_FILE) $(SYS_FTOFF_FILE) $(SYS_SCRIPTS_FILE) + -rm -f $(SYS_INDOFF_FILE) $(SYS_INDENT_FILE) + -rm -f $(SYS_FTPLUGOF_FILE) $(SYS_FTPLUGIN_FILE) + -rm -f $(SYS_OPTWIN_FILE) + -rm -f $(DEST_COL)/*.vim $(DEST_COL)/README.txt + -rm -rf $(DEST_COL)/tools + -rm -rf $(DEST_COL)/lists + -rm -f $(DEST_SYN)/shared/*.vim $(DEST_SYN)/shared/README.txt + -rm -f $(DEST_SYN)/*.vim $(DEST_SYN)/README.txt + -rm -f $(DEST_IND)/*.vim $(DEST_IND)/README.txt + -rm -rf $(DEST_MACRO) + -rm -rf $(DEST_PACK) + -rm -rf $(DEST_TUTOR) + -rm -rf $(DEST_SPELL) + -rm -rf $(DEST_TOOLS) + -rm -rf $(DEST_LANG) + -rm -rf $(DEST_KMAP) + -rm -rf $(DEST_COMP) + -rm -f $(DEST_PRINT)/*.ps + -rmdir $(DEST_HELP) $(DEST_PRINT) $(DEST_COL) $(DEST_SYN)/shared + -rmdir $(DEST_SYN) $(DEST_IND) + -rm -rf $(DEST_FTP)/*.vim $(DEST_FTP)/README.txt $(DEST_FTP)/logtalk.dict + -rm -f $(DEST_AUTO)/*.vim $(DEST_AUTO)/README.txt + -rm -f $(DEST_AUTO)/dist/*.vim $(DEST_AUTO)/xml/*.vim + -rm -f $(DEST_IMPORT)/dist/*.vim + -rm -f $(DEST_PLUG)/*.vim $(DEST_PLUG)/README.txt + -rmdir $(DEST_FTP) $(DEST_AUTO)/dist $(DEST_AUTO)/xml $(DEST_AUTO) + -rmdir $(DEST_IMPORT)/dist $(DEST_IMPORT) + -rmdir $(DEST_PLUG) $(DEST_RT) +# This will fail when other Vim versions are installed, no worries. + -rmdir $(DEST_VIM) + +# Clean up all the files that have been produced, except configure's. +# We support common typing mistakes for Juergen! :-) +clean celan: testclean + -rm -f *.o core $(VIMTARGET).core $(VIMTARGET) vim xxd/*.o + -rm -rf objects + -rm -f $(TOOLS) auto/osdef.h auto/pathdef.c auto/if_perl.c auto/gui_gtk_gresources.c auto/gui_gtk_gresources.h auto/os_haiku.rdef + -rm -f conftest* *~ auto/link.sed + -rm -f testdir/opt_test.vim + -rm -f $(UNITTEST_TARGETS) + -rm -f runtime pixmaps + -rm -f mzscheme_base.c + -rm -rf libvterm/.libs libterm/t/.libs libvterm/src/*.o libvterm/src/*.lo libvterm/t/*.o libvterm/t/*.lo libvterm/t/harness libvterm/libvterm.la + if test -d $(PODIR); then \ + cd $(PODIR); $(MAKE) prefix=$(DESTDIR)$(prefix) clean; \ + fi + +# Make a shadow directory for compilation on another system or with different +# features: +# % make shadow +# % cd shadow +# edit configuration in src/shadow/Makefile +# % make +# +# Alternatively use a link for the Makefile and run configure with flags in +# another way. When new source files are added use "shadowupdate": +# % cd shadow +# % rm Makefile +# % ln -s ../Makefile . +# % ./configure {options} +# % make +# And later: +# % git pull +# % make distclean shadowupdate +# % ./configure {options} +# % make +SHADOWDIR = shadow + +LINKEDFILES = ../*.[chm] ../*.cc ../*.in ../*.sh ../*.xs ../*.xbm ../gui_gtk_res.xml ../toolcheck ../proto ../libvterm ../vimtutor ../gvimtutor ../install-sh ../Make_all.mak + +shadow: runtime pixmaps + $(MKDIR_P) $(SHADOWDIR) + cd $(SHADOWDIR); ln -s $(LINKEDFILES) . + mkdir $(SHADOWDIR)/auto + cd $(SHADOWDIR)/auto; ln -s ../../auto/configure . + $(MKDIR_P) $(SHADOWDIR)/po + cd $(SHADOWDIR)/po; ln -s ../../po/*.po ../../po/*.mak ../../po/*.vim ../../po/*.in ../../po/Makefile ../../po/*.c . + cd $(SHADOWDIR); rm -f auto/link.sed + cp Makefile configure $(SHADOWDIR) + rm -f $(SHADOWDIR)/auto/config.mk $(SHADOWDIR)/config.mk.dist + cp config.mk.dist $(SHADOWDIR)/auto/config.mk + cp config.mk.dist $(SHADOWDIR) + $(MKDIR_P) $(SHADOWDIR)/xxd + cd $(SHADOWDIR)/xxd; ln -s ../../xxd/*.[ch] ../../xxd/Make* . + $(MKDIR_P) $(SHADOWDIR)/xdiff + cd $(SHADOWDIR)/xdiff; ln -s ../../xdiff/*.[ch] . + $(MKDIR_P) $(SHADOWDIR)/testdir + cd $(SHADOWDIR)/testdir; ln -s ../../testdir/Makefile \ + ../../testdir/Make_all.mak \ + ../../testdir/README.txt \ + ../../testdir/*.in \ + ../../testdir/*.vim \ + ../../testdir/*.py \ + ../../testdir/python* \ + ../../testdir/pyxfile \ + ../../testdir/sautest \ + ../../testdir/samples \ + ../../testdir/dumps \ + ../../testdir/*.ok \ + ../../testdir/testluaplugin \ + . + +# After updating Vim new files may have been created, use this to refresh the +# symbolic links in the shadow directory. This isn't guaranteed to catch all +# changes, running "make shadow" again might sometimes be needed. +shadowupdate: + ln -sf $(LINKEDFILES) . + +# Link needed for doing "make install" in a shadow directory. +runtime: + -ln -s ../runtime . + +# Link needed for doing "make" using GTK in a shadow directory. +pixmaps: + -ln -s ../pixmaps . + +# Update the synmenu.vim file with the latest Syntax menu. +# This is only needed when runtime/makemenu.vim was changed. +menu: ./vim ../runtime/makemenu.vim + ./vim --clean -X --not-a-term -S ../runtime/makemenu.vim + +# Start configure from scratch +scrub scratch: + -rm -f auto/config.status auto/config.cache config.log auto/config.log + -rm -f auto/config.h auto/link.log auto/link.sed auto/config.mk + touch auto/config.h + cp config.mk.dist auto/config.mk + +distclean: clean scratch + -rm -f tags + +dist: distclean + @echo + @echo Making the distribution has to be done in the top directory + +mdepend: + -@rm -f Makefile~ + cp Makefile Makefile~ + sed -e '/\#\#\# Dependencies/q' < Makefile > tmp_make + @for i in $(ALL_SRC) ; do \ + echo "$$i" ; \ + echo `echo "$$i" | sed -e 's/[^ ]*\.c$$/objects\/\1.o/'`": $$i" `\ + $(CPP) $$i |\ + grep '^# .*"\./.*\.h"' |\ + sort -t'"' -u +1 -2 |\ + sed -e 's/.*"\.\/\(.*\)".*/\1/'\ + ` >> tmp_make ; \ + done + mv tmp_make Makefile + +depend: + -@rm -f Makefile~ + cp Makefile Makefile~ + sed -e '/\#\#\# Dependencies/q' < Makefile > tmp_make + -for i in $(ALL_LOCAL_SRC); do echo $$i; \ + $(CPP_DEPEND) $$i | \ + sed -e 's+^\([^ ]*\.o\)+objects/\1+' >> tmp_make; done + -for i in $(TERM_SRC); do echo $$i; \ + $(CPP_DEPEND) $$i | \ + sed -e 's+^\([^ ]*\.o\)+objects/vterm_\1+' >> tmp_make; done + -for i in $(XDIFF_SRC); do echo $$i; \ + $(CPP_DEPEND) $$i | \ + sed -e 's+^\([^ ]*\.o\)+objects/\1+' -e 's+xdiff/\.\./++g' >> tmp_make; done + mv tmp_make Makefile + +# Run lint. Clean up the *.ln files that are sometimes left behind. +lint: + $(LINT) $(LINT_OPTIONS) $(LINT_CFLAGS) $(LINT_EXTRA) $(LINT_SRC) + -rm -f *.ln + +# Check dosinst.c with lint. +lintinstall: + $(LINT) $(LINT_OPTIONS) -DWIN32 -DUNIX_LINT dosinst.c + -rm -f dosinst.ln + +########################################################################### + +.c.o: + $(CCC) $< + +auto/if_perl.c: if_perl.xs + $(PERL) -e 'unless ( $$] >= 5.005 ) { for (qw(na defgv errgv)) { print "#define PL_$$_ $$_\n" }}' > $@ + $(PERL) $(PERL_XSUBPP) -prototypes -typemap \ + $(PERLLIB)/ExtUtils/typemap if_perl.xs >> $@ + +auto/osdef.h: auto/config.h osdef.sh osdef1.h.in osdef2.h.in + CC="$(CC) $(OSDEF_CFLAGS)" srcdir=$(srcdir) sh $(srcdir)/osdef.sh + +auto/os_haiku.rdef: os_haiku.rdef.in + @echo creating $@ + @echo '/* This file is automatically created by Makefile */' >> $@ + @echo '/* DO NOT EDIT! Change Makefile only. */' >> $@ + @cat $(srcdir)/os_haiku.rdef.in >> auto/os_haiku.rdef + sed -i "s|@MAJOR@|$(VIMMAJOR)|" auto/os_haiku.rdef + sed -i "s|@MINOR@|$(VIMMINOR)|" auto/os_haiku.rdef + +auto/pathdef.c: Makefile auto/config.mk + -@echo creating $@ + -@echo '/* pathdef.c */' > $@ + -@echo '/* This file is automatically created by Makefile' >> $@ + -@echo ' * DO NOT EDIT! Change Makefile only. */' >> $@ + -@echo '#include "vim.h"' >> $@ + -@echo 'char_u *default_vim_dir = (char_u *)"$(VIMRCLOC)";' | $(QUOTESED) >> $@ + -@echo 'char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR)";' | $(QUOTESED) >> $@ + -@echo 'char_u *all_cflags = (char_u *)"$(CC) -c -I$(srcdir) $(ALL_CFLAGS)";' | $(QUOTESED) >> $@ + -@echo 'char_u *all_lflags = (char_u *)"$(CC) $(ALL_LIB_DIRS) $(LDFLAGS) -o $(VIMTARGET) $(ALL_LIBS) ";' | $(QUOTESED) >> $@ + -@echo 'char_u *compiled_user = (char_u *)"' | tr -d $(NL) >> $@ + -@if test -n "$(COMPILEDBY)"; then \ + echo "$(COMPILEDBY)" | tr -d $(NL) >> $@; \ + else ((logname) 2>/dev/null || whoami) | tr -d $(NL) >> $@; fi + -@echo '";' >> $@ + -@echo 'char_u *compiled_sys = (char_u *)"' | tr -d $(NL) >> $@ + -@if test -z "$(COMPILEDBY)"; then hostname | tr -d $(NL) >> $@; fi + -@echo '";' >> $@ + -@sh $(srcdir)/pathdef.sh + +GUI_GTK_RES_INPUTS = \ + ../pixmaps/stock_vim_build_tags.png \ + ../pixmaps/stock_vim_find_help.png \ + ../pixmaps/stock_vim_save_all.png \ + ../pixmaps/stock_vim_session_load.png \ + ../pixmaps/stock_vim_session_new.png \ + ../pixmaps/stock_vim_session_save.png \ + ../pixmaps/stock_vim_shell.png \ + ../pixmaps/stock_vim_window_maximize.png \ + ../pixmaps/stock_vim_window_maximize_width.png \ + ../pixmaps/stock_vim_window_minimize.png \ + ../pixmaps/stock_vim_window_minimize_width.png \ + ../pixmaps/stock_vim_window_split.png \ + ../pixmaps/stock_vim_window_split_vertical.png + +auto/gui_gtk_gresources.c: gui_gtk_res.xml $(GUI_GTK_RES_INPUTS) + $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=../pixmaps --generate --c-name=gui_gtk --manual-register gui_gtk_res.xml +auto/gui_gtk_gresources.h: gui_gtk_res.xml $(GUI_GTK_RES_INPUTS) + if test -z "$(GLIB_COMPILE_RESOURCES)"; then touch $@; else \ + $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=../pixmaps --generate --c-name=gui_gtk --manual-register gui_gtk_res.xml; \ + fi + +# Dependencies through vim.h that most targets depend on. Used by targets +# that are not taken care of by "make depend". +VIM_H_DEPENDENCIES = \ + vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ + proto.h globals.h errors.h + +# All the object files are put in the "objects" directory. Since not all make +# commands understand putting object files in another directory, it must be +# specified for each file separately. + +objects: objects/.dirstamp + +objects/.dirstamp: + $(MKDIR_P) objects + touch objects/.dirstamp + +# All object files depend on the objects directory, so that parallel make +# works. Can't depend on the directory itself, its timestamp changes all the +# time. +$(ALL_OBJ): objects/.dirstamp + +objects/alloc.o: alloc.c + $(CCC) -o $@ alloc.c + +objects/arabic.o: arabic.c + $(CCC) -o $@ arabic.c + +objects/arglist.o: arglist.c + $(CCC) -o $@ arglist.c + +objects/autocmd.o: autocmd.c + $(CCC) -o $@ autocmd.c + +objects/blob.o: blob.c + $(CCC) -o $@ blob.c + +objects/blowfish.o: blowfish.c + $(CCC) -o $@ blowfish.c + +objects/buffer.o: buffer.c + $(CCC) -o $@ buffer.c + +objects/bufwrite.o: bufwrite.c + $(CCC) -o $@ bufwrite.c + +objects/change.o: change.c + $(CCC) -o $@ change.c + +objects/charset.o: charset.c + $(CCC) -o $@ charset.c + +objects/cindent.o: cindent.c + $(CCC) -o $@ cindent.c + +objects/clientserver.o: clientserver.c + $(CCC) -o $@ clientserver.c + +objects/clipboard.o: clipboard.c + $(CCC) -o $@ clipboard.c + +objects/cmdexpand.o: cmdexpand.c + $(CCC) -o $@ cmdexpand.c + +objects/cmdhist.o: cmdhist.c + $(CCC) -o $@ cmdhist.c + +objects/crypt.o: crypt.c + $(CCC) -o $@ crypt.c + +objects/crypt_zip.o: crypt_zip.c + $(CCC) -o $@ crypt_zip.c + +objects/debugger.o: debugger.c + $(CCC) -o $@ debugger.c + +objects/dict.o: dict.c + $(CCC) -o $@ dict.c + +objects/diff.o: diff.c $(XDIFF_INCL) + $(CCC) -o $@ diff.c + +objects/digraph.o: digraph.c + $(CCC) -o $@ digraph.c + +objects/drawline.o: drawline.c + $(CCC) -o $@ drawline.c + +objects/drawscreen.o: drawscreen.c + $(CCC) -o $@ drawscreen.c + +objects/edit.o: edit.c + $(CCC) -o $@ edit.c + +objects/eval.o: eval.c + $(CCC) -o $@ eval.c + +objects/evalbuffer.o: evalbuffer.c + $(CCC) -o $@ evalbuffer.c + +objects/evalfunc.o: evalfunc.c + $(CCC) -o $@ evalfunc.c + +objects/evalvars.o: evalvars.c + $(CCC) -o $@ evalvars.c + +objects/evalwindow.o: evalwindow.c + $(CCC) -o $@ evalwindow.c + +objects/ex_cmds.o: ex_cmds.c + $(CCC) -o $@ ex_cmds.c + +objects/ex_cmds2.o: ex_cmds2.c + $(CCC) -o $@ ex_cmds2.c + +objects/ex_docmd.o: ex_docmd.c + $(CCC) -o $@ ex_docmd.c + +objects/ex_eval.o: ex_eval.c + $(CCC) -o $@ ex_eval.c + +objects/ex_getln.o: ex_getln.c + $(CCC) -o $@ ex_getln.c + +objects/fileio.o: fileio.c + $(CCC) -o $@ fileio.c + +objects/filepath.o: filepath.c + $(CCC) -o $@ filepath.c + +objects/findfile.o: findfile.c + $(CCC) -o $@ findfile.c + +objects/float.o: float.c + $(CCC) -o $@ float.c + +objects/fold.o: fold.c + $(CCC) -o $@ fold.c + +objects/getchar.o: getchar.c + $(CCC) -o $@ getchar.c + +objects/hardcopy.o: hardcopy.c + $(CCC) -o $@ hardcopy.c + +objects/hashtab.o: hashtab.c + $(CCC) -o $@ hashtab.c + +objects/help.o: help.c + $(CCC) -o $@ help.c + +objects/gui.o: gui.c + $(CCC) -o $@ gui.c + +objects/beval.o: beval.c + $(CCC) -o $@ beval.c + +objects/gui_beval.o: gui_beval.c + $(CCC) -o $@ gui_beval.c + +objects/gui_gtk.o: gui_gtk.c + $(CCC) -o $@ gui_gtk.c + +objects/gui_gtk_f.o: gui_gtk_f.c + $(CCC) -o $@ gui_gtk_f.c + +objects/gui_gtk_gresources.o: auto/gui_gtk_gresources.c + $(CCC_NF) $(PERL_CFLAGS) $(ALL_CFLAGS) -o $@ auto/gui_gtk_gresources.c + +objects/gui_gtk_x11.o: gui_gtk_x11.c + $(CCC) -o $@ gui_gtk_x11.c + +objects/gui_haiku.o: gui_haiku.cc + $(CCC) -o $@ gui_haiku.cc + +objects/gui_motif.o: gui_motif.c + $(CCC) -o $@ gui_motif.c + +objects/gui_xmdlg.o: gui_xmdlg.c + $(CCC) -o $@ gui_xmdlg.c + +objects/gui_xmebw.o: gui_xmebw.c + $(CCC) -o $@ gui_xmebw.c + +objects/gui_x11.o: gui_x11.c + $(CCC) -o $@ gui_x11.c + +objects/gui_xim.o: gui_xim.c + $(CCC) -o $@ gui_xim.c + +objects/gui_photon.o: gui_photon.c + $(CCC) -o $@ gui_photon.c + +objects/highlight.o: highlight.c + $(CCC) -o $@ highlight.c + +objects/if_cscope.o: if_cscope.c + $(CCC) -o $@ if_cscope.c + +objects/if_xcmdsrv.o: if_xcmdsrv.c + $(CCC) -o $@ if_xcmdsrv.c + +objects/if_lua.o: if_lua.c + $(CCC_NF) $(LUA_CFLAGS) $(ALL_CFLAGS) $(LUA_CFLAGS_EXTRA) -o $@ if_lua.c + +objects/if_mzsch.o: if_mzsch.c $(MZSCHEME_EXTRA) + $(CCC) -o $@ $(MZSCHEME_CFLAGS_EXTRA) if_mzsch.c + +mzscheme_base.c: + $(MZSCHEME_MZC) --c-mods mzscheme_base.c ++lib scheme/base + +objects/if_perl.o: auto/if_perl.c + $(CCC_NF) $(PERL_CFLAGS) $(ALL_CFLAGS) $(PERL_CFLAGS_EXTRA) -o $@ auto/if_perl.c + +objects/if_perlsfio.o: if_perlsfio.c + $(CCC_NF) $(PERL_CFLAGS) $(ALL_CFLAGS) $(PERL_CFLAGS_EXTRA) -o $@ if_perlsfio.c + +objects/if_python.o: if_python.c if_py_both.h + $(CCC_NF) $(PYTHON_CFLAGS) $(ALL_CFLAGS) $(PYTHON_CFLAGS_EXTRA) -o $@ if_python.c + +objects/if_python3.o: if_python3.c if_py_both.h + $(CCC_NF) $(PYTHON3_CFLAGS) $(ALL_CFLAGS) $(PYTHON3_CFLAGS_EXTRA) -o $@ if_python3.c + +objects/if_ruby.o: if_ruby.c + $(CCC_NF) $(RUBY_CFLAGS) $(ALL_CFLAGS) $(RUBY_CFLAGS_EXTRA) -o $@ if_ruby.c + +objects/if_tcl.o: if_tcl.c + $(CCC_NF) $(TCL_CFLAGS) $(ALL_CFLAGS) $(TCL_CFLAGS_EXTRA) -o $@ if_tcl.c + +objects/indent.o: indent.c + $(CCC) -o $@ indent.c + +objects/insexpand.o: insexpand.c + $(CCC) -o $@ insexpand.c + +objects/job.o: job.c + $(CCC) -o $@ job.c + +objects/json.o: json.c + $(CCC) -o $@ json.c + +objects/json_test.o: json_test.c + $(CCC) -o $@ json_test.c + +objects/kword_test.o: kword_test.c + $(CCC) -o $@ kword_test.c + +objects/list.o: list.c + $(CCC) -o $@ list.c + +objects/locale.o: locale.c + $(CCC) -o $@ locale.c + +objects/logfile.o: logfile.c + $(CCC) -o $@ logfile.c + +objects/main.o: main.c + $(CCC) -o $@ main.c + +objects/map.o: map.c + $(CCC) -o $@ map.c + +objects/mark.o: mark.c + $(CCC) -o $@ mark.c + +objects/match.o: match.c + $(CCC) -o $@ match.c + +objects/memfile.o: memfile.c + $(CCC) -o $@ memfile.c + +objects/memfile_test.o: memfile_test.c + $(CCC) -o $@ memfile_test.c + +objects/memline.o: memline.c + $(CCC) -o $@ memline.c + +objects/menu.o: menu.c + $(CCC) -o $@ menu.c + +objects/message.o: message.c + $(CCC) -o $@ message.c + +objects/message_test.o: message_test.c + $(CCC) -o $@ message_test.c + +objects/misc1.o: misc1.c + $(CCC) -o $@ misc1.c + +objects/misc2.o: misc2.c + $(CCC) -o $@ misc2.c + +objects/mouse.o: mouse.c + $(CCC) -o $@ mouse.c + +objects/move.o: move.c + $(CCC) -o $@ move.c + +objects/mbyte.o: mbyte.c + $(CCC) -o $@ mbyte.c + +objects/normal.o: normal.c + $(CCC) -o $@ normal.c + +objects/ops.o: ops.c + $(CCC) -o $@ ops.c + +objects/option.o: option.c optiondefs.h + $(CCC_NF) $(ALL_IF_CFLAGS) $(ALL_CFLAGS) $(ALL_IF_CFLAGS_EXTRA) -o $@ option.c + +objects/optionstr.o: optionstr.c + $(CCC_NF) $(ALL_IF_CFLAGS) $(ALL_CFLAGS) $(ALL_IF_CFLAGS_EXTRA) -o $@ optionstr.c + +objects/os_qnx.o: os_qnx.c $(VIM_H_DEPENDENCIES) + $(CCC) -o $@ os_qnx.c + +objects/os_haiku.rsrc: auto/os_haiku.rdef + cat $< | $(CCC) -E - | grep -v '^#' | rc -o "$@" - + +objects/os_macosx.o: os_macosx.m + $(CCC) -o $@ os_macosx.m + +objects/os_mac_conv.o: os_mac_conv.c $(VIM_H_DEPENDENCIES) + $(CCC) -o $@ os_mac_conv.c + +objects/os_unix.o: os_unix.c + $(CCC) -o $@ os_unix.c + +objects/os_mswin.o: os_mswin.c $(VIM_H_DEPENDENCIES) + $(CCC) -o $@ os_mswin.c + +objects/winclip.o: winclip.c $(VIM_H_DEPENDENCIES) + $(CCC) -o $@ winclip.c + +objects/pathdef.o: auto/pathdef.c + $(CCC) -o $@ auto/pathdef.c + +objects/popupmenu.o: popupmenu.c + $(CCC) -o $@ popupmenu.c + +objects/popupwin.o: popupwin.c + $(CCC) -o $@ popupwin.c + +objects/profiler.o: profiler.c + $(CCC) -o $@ profiler.c + +objects/pty.o: pty.c + $(CCC) -o $@ pty.c + +objects/quickfix.o: quickfix.c + $(CCC) -o $@ quickfix.c + +objects/regexp.o: regexp.c regexp_bt.c regexp_nfa.c + $(CCC) -o $@ regexp.c + +objects/register.o: register.c + $(CCC) -o $@ register.c + +objects/scriptfile.o: scriptfile.c + $(CCC) -o $@ scriptfile.c + +objects/screen.o: screen.c + $(CCC) -o $@ screen.c + +objects/search.o: search.c + $(CCC) -o $@ search.c + +objects/session.o: session.c + $(CCC) -o $@ session.c + +objects/sha256.o: sha256.c + $(CCC) -o $@ sha256.c + +objects/sign.o: sign.c + $(CCC) -o $@ sign.c + +objects/sound.o: sound.c + $(CCC) -o $@ sound.c + +objects/spell.o: spell.c + $(CCC) -o $@ spell.c + +objects/spellfile.o: spellfile.c + $(CCC) -o $@ spellfile.c + +objects/spellsuggest.o: spellsuggest.c + $(CCC) -o $@ spellsuggest.c + +objects/strings.o: strings.c + $(CCC) -o $@ strings.c + +objects/syntax.o: syntax.c + $(CCC) -o $@ syntax.c + +objects/tag.o: tag.c + $(CCC) -o $@ tag.c + +objects/term.o: term.c + $(CCC) -o $@ term.c + +objects/terminal.o: terminal.c $(TERM_DEPS) + $(CCC) -o $@ terminal.c + +objects/testing.o: testing.c + $(CCC) -o $@ testing.c + +objects/textformat.o: textformat.c + $(CCC) -o $@ textformat.c + +objects/textobject.o: textobject.c + $(CCC) -o $@ textobject.c + +objects/textprop.o: textprop.c + $(CCC) -o $@ textprop.c + +objects/time.o: time.c + $(CCC) -o $@ time.c + +objects/typval.o: typval.c + $(CCC) -o $@ typval.c + +objects/ui.o: ui.c + $(CCC) -o $@ ui.c + +objects/undo.o: undo.c + $(CCC) -o $@ undo.c + +objects/usercmd.o: usercmd.c + $(CCC) -o $@ usercmd.c + +objects/userfunc.o: userfunc.c + $(CCC) -o $@ userfunc.c + +objects/vim9class.o: vim9class.c + $(CCC) -o $@ vim9class.c + +objects/vim9cmds.o: vim9cmds.c + $(CCC) -o $@ vim9cmds.c + +objects/vim9compile.o: vim9compile.c + $(CCC) -o $@ vim9compile.c + +objects/vim9execute.o: vim9execute.c + $(CCC) -o $@ vim9execute.c + +objects/vim9expr.o: vim9expr.c + $(CCC) -o $@ vim9expr.c + +objects/vim9instr.o: vim9instr.c + $(CCC) -o $@ vim9instr.c + +objects/vim9script.o: vim9script.c + $(CCC) -o $@ vim9script.c + +objects/vim9type.o: vim9type.c + $(CCC) -o $@ vim9type.c + +objects/viminfo.o: viminfo.c + $(CCC) -o $@ viminfo.c + +objects/window.o: window.c + $(CCC) -o $@ window.c + +objects/netbeans.o: netbeans.c + $(CCC) -o $@ netbeans.c + +objects/channel.o: channel.c + $(CCC) -o $@ channel.c + +# Dependencies that "make depend" doesn't find +objects/gui_gtk_x11.o: version.h + + +# Build rules for libvterm. Putting them here allows for adding compilation +# options specific for Vim. Since the .o files go into objects/ we do need to +# prefix vterm_ to avoid name clashes. +CCCTERM = $(CCC_NF) $(VTERM_CFLAGS) $(ALL_CFLAGS) -DINLINE="" \ + -DVSNPRINTF=vim_vsnprintf \ + -DSNPRINTF=vim_snprintf \ + -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ + -DWCWIDTH_FUNCTION=utf_uint2cells + +objects/vterm_encoding.o: libvterm/src/encoding.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/encoding.c + +objects/vterm_keyboard.o: libvterm/src/keyboard.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/keyboard.c + +objects/vterm_mouse.o: libvterm/src/mouse.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/mouse.c + +objects/vterm_parser.o: libvterm/src/parser.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/parser.c + +objects/vterm_pen.o: libvterm/src/pen.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/pen.c + +objects/vterm_screen.o: libvterm/src/screen.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/screen.c + +objects/vterm_state.o: libvterm/src/state.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/state.c + +objects/vterm_unicode.o: libvterm/src/unicode.c $(TERM_DEPS) libvterm/src/fullwidth.inc + $(CCCTERM) -o $@ libvterm/src/unicode.c + +objects/vterm_vterm.o: libvterm/src/vterm.c $(TERM_DEPS) + $(CCCTERM) -o $@ libvterm/src/vterm.c + +CCCDIFF = $(CCC_NF) $(ALL_CFLAGS) + +objects/xdiffi.o: xdiff/xdiffi.c $(XDIFF_INCL) + $(CCCDIFF) -o $@ xdiff/xdiffi.c + +objects/xprepare.o: xdiff/xprepare.c $(XDIFF_INCL) + $(CCCDIFF) -o $@ xdiff/xprepare.c + +objects/xutils.o: xdiff/xutils.c $(XDIFF_INCL) + $(CCCDIFF) -o $@ xdiff/xutils.c + +objects/xemit.o: xdiff/xemit.c $(XDIFF_INCL) + $(CCCDIFF) -o $@ xdiff/xemit.c + +objects/xhistogram.o: xdiff/xhistogram.c $(XDIFF_INCL) + $(CCCDIFF) -o $@ xdiff/xhistogram.c + +objects/xpatience.o: xdiff/xpatience.c $(XDIFF_INCL) + $(CCCDIFF) -o $@ xdiff/xpatience.c + + +Makefile: + @echo 'The name of the makefile MUST be "Makefile" (with capital M)!' + + +############################################################################### +# +# Haiku installation +# +# This rule: +# - add resources to already installed vim binary to avoid +# stripping them during install; +# - update system MIME database with info about vim application. +# +install_haiku_extra: $(DEST_BIN)/$(VIMTARGET) objects/os_haiku.rsrc + xres -o $(DEST_BIN)/$(VIMTARGET) objects/os_haiku.rsrc + mimeset $(DEST_BIN)/$(VIMTARGET) + +# List of g*-links that should be replaced with shell script equivalents. +# This solves the problem of them from Tracker. +# +HAIKU_GLINKS = $(DEST_BIN)/$(GVIMTARGET) \ + $(DEST_BIN)/$(GVIEWTARGET) \ + $(DEST_BIN)/$(GVIMDIFFTARGET) \ + $(DEST_BIN)/$(RGVIMTARGET) \ + $(DEST_BIN)/$(RGVIEWTARGET) + +# This rule: +# - Replace gvim link with copy of vim binary. +# - Replace g*-links with shell script equivalents to solve the +# problem of calling them from Tracker, +# - Add icon resources to mentioned g*-link shell scripts +# - in case gui-less vim.con executable available use it. +# +installglinks_haiku: $(HAIKU_GLINKS) install_haiku_extra + @catattr -r "BEOS:ICON" $(DEST_BIN)/$(GVIMTARGET) > ~icon.attr + for i in $(HAIKU_GLINKS); do \ + rm $$i ; \ + echo "#!/bin/sh" > $$i ; \ + case $$i in \ + $(DEST_BIN)/$(GVIMTARGET)) \ + cp $(DEST_BIN)/$(VIMTARGET) $$i ; \ + if [ -f $(VIMTARGET).con ] ; then \ + $(STRIP) $(VIMTARGET).con ; \ + mv $(VIMTARGET).con $(DEST_BIN)/$(VIMTARGET) ; \ + fi ;; \ + $(DEST_BIN)/$(GVIEWTARGET)) printf "%s -R %c%c" $(GVIMTARGET) '$$' '*' >> $$i;; \ + $(DEST_BIN)/$(GVIMDIFFTARGET)) printf "%s -d %c%c" $(GVIMTARGET) '$$' '*' >> $$i;; \ + $(DEST_BIN)/$(RGVIMTARGET)) printf "%s -Z %c%c" $(GVIMTARGET) '$$' '*' >> $$i;; \ + $(DEST_BIN)/$(RGVIEWTARGET)) printf "%s -Z -R %c%c" $(GVIMTARGET) '$$' '*' >> $$i;; \ + *) printf "%s %c%c" $(GVIMTARGET) '$$' '*' >> $$i;; \ + esac ; \ + chmod $(BINMOD) $$i ; \ + addattr -f ~icon.attr -t \'VICN\' BEOS:ICON $$i ; \ + done + addattr -f ~icon.attr -t \'VICN\' BEOS:ICON $(DEST_BIN)/$(VIMNAME)tutor + @rm ~icon.attr + +############################################################################### +### (automatically generated by 'make depend') +### Dependencies: +objects/alloc.o: alloc.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/arabic.o: arabic.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/arglist.o: arglist.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/autocmd.o: autocmd.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/beval.o: beval.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/blob.o: blob.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/blowfish.o: blowfish.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/buffer.o: buffer.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/change.o: change.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/charset.o: charset.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/cindent.o: cindent.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/clientserver.o: clientserver.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/clipboard.o: clipboard.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/cmdexpand.o: cmdexpand.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/cmdhist.o: cmdhist.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/crypt.o: crypt.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/crypt_zip.o: crypt_zip.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/debugger.o: debugger.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/dict.o: dict.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/diff.o: diff.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h xdiff/xdiff.h xdiff/../vim.h +objects/digraph.o: digraph.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/drawline.o: drawline.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/drawscreen.o: drawscreen.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/edit.o: edit.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/eval.o: eval.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/evalbuffer.o: evalbuffer.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/evalfunc.o: evalfunc.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/evalvars.o: evalvars.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/evalwindow.o: evalwindow.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/ex_cmds.o: ex_cmds.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/ex_cmds2.o: ex_cmds2.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/ex_docmd.o: ex_docmd.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h ex_cmdidxs.h +objects/ex_eval.o: ex_eval.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/ex_getln.o: ex_getln.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/fileio.o: fileio.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/filepath.o: filepath.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/findfile.o: findfile.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/float.o: float.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/fold.o: fold.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/getchar.o: getchar.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/gui_xim.o: gui_xim.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/hardcopy.o: hardcopy.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/hashtab.o: hashtab.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/help.o: help.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/highlight.o: highlight.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/if_cscope.o: if_cscope.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/if_xcmdsrv.o: if_xcmdsrv.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h version.h +objects/indent.o: indent.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/insexpand.o: insexpand.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/json.o: json.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/list.o: list.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/locale.o: locale.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/logfile.o: logfile.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/main.o: main.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/map.o: map.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/mark.o: mark.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/match.o: match.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/mbyte.o: mbyte.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/memfile.o: memfile.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/memline.o: memline.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/menu.o: menu.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/message.o: message.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/misc1.o: misc1.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/misc2.o: misc2.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/mouse.o: mouse.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/move.o: move.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/normal.o: normal.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h nv_cmds.h nv_cmdidxs.h +objects/ops.o: ops.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/option.o: option.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h optiondefs.h +objects/optionstr.o: optionstr.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/os_unix.o: os_unix.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h os_unixx.h +objects/pathdef.o: auto/pathdef.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/popupmenu.o: popupmenu.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/popupwin.o: popupwin.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/profiler.o: profiler.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/pty.o: pty.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/quickfix.o: quickfix.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/regexp.o: regexp.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h regexp_bt.c regexp_nfa.c +objects/register.o: register.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/screen.o: screen.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/scriptfile.o: scriptfile.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/search.o: search.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/session.o: session.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/sha256.o: sha256.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/sign.o: sign.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/sound.o: sound.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/spell.o: spell.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/spellfile.o: spellfile.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/spellsuggest.o: spellsuggest.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/strings.o: strings.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/syntax.o: syntax.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/tag.o: tag.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/term.o: term.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/terminal.o: terminal.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/testing.o: testing.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/textformat.o: textformat.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/textobject.o: textobject.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/textprop.o: textprop.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/time.o: time.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/typval.o: typval.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/ui.o: ui.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/undo.o: undo.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/usercmd.o: usercmd.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/userfunc.o: userfunc.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/version.o: version.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/vim9class.o: vim9class.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h vim9.h +objects/vim9cmds.o: vim9cmds.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h vim9.h +objects/vim9compile.o: vim9compile.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h vim9.h +objects/vim9execute.o: vim9execute.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h vim9.h +objects/vim9expr.o: vim9expr.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h vim9.h +objects/vim9instr.o: vim9instr.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h vim9.h +objects/vim9script.o: vim9script.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h vim9.h +objects/vim9type.o: vim9type.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h vim9.h +objects/viminfo.o: viminfo.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/window.o: window.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/bufwrite.o: bufwrite.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/gui.o: gui.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/gui_gtk.o: gui_gtk.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h gui_gtk_f.h +objects/gui_gtk_f.o: gui_gtk_f.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h gui_gtk_f.h +objects/gui_motif.o: gui_motif.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h gui_xmebw.h \ + ../pixmaps/alert.xpm ../pixmaps/error.xpm ../pixmaps/generic.xpm \ + ../pixmaps/info.xpm ../pixmaps/quest.xpm gui_x11_pm.h \ + ../pixmaps/tb_new.xpm ../pixmaps/tb_open.xpm ../pixmaps/tb_close.xpm \ + ../pixmaps/tb_save.xpm ../pixmaps/tb_print.xpm ../pixmaps/tb_cut.xpm \ + ../pixmaps/tb_copy.xpm ../pixmaps/tb_paste.xpm ../pixmaps/tb_find.xpm \ + ../pixmaps/tb_find_next.xpm ../pixmaps/tb_find_prev.xpm \ + ../pixmaps/tb_find_help.xpm ../pixmaps/tb_exit.xpm \ + ../pixmaps/tb_undo.xpm ../pixmaps/tb_redo.xpm ../pixmaps/tb_help.xpm \ + ../pixmaps/tb_macro.xpm ../pixmaps/tb_make.xpm \ + ../pixmaps/tb_save_all.xpm ../pixmaps/tb_jump.xpm \ + ../pixmaps/tb_ctags.xpm ../pixmaps/tb_load_session.xpm \ + ../pixmaps/tb_save_session.xpm ../pixmaps/tb_new_session.xpm \ + ../pixmaps/tb_blank.xpm ../pixmaps/tb_maximize.xpm \ + ../pixmaps/tb_split.xpm ../pixmaps/tb_minimize.xpm \ + ../pixmaps/tb_shell.xpm ../pixmaps/tb_replace.xpm \ + ../pixmaps/tb_vsplit.xpm ../pixmaps/tb_maxwidth.xpm \ + ../pixmaps/tb_minwidth.xpm +objects/gui_xmdlg.o: gui_xmdlg.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/gui_xmebw.o: gui_xmebw.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h gui_xmebwp.h gui_xmebw.h +objects/gui_gtk_x11.o: gui_gtk_x11.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h auto/gui_gtk_gresources.h \ + gui_gtk_f.h ../runtime/vim32x32.xpm ../runtime/vim16x16.xpm \ + ../runtime/vim48x48.xpm +objects/gui_x11.o: gui_x11.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h ../runtime/vim32x32.xpm ../runtime/vim16x16.xpm \ + ../runtime/vim48x48.xpm +objects/gui_haiku.o: gui_haiku.cc vim.h protodef.h auto/config.h feature.h \ + os_unix.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/json_test.o: json_test.c main.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h json.c +objects/kword_test.o: kword_test.c main.c vim.h protodef.h auto/config.h \ + feature.h os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h \ + option.h beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h charset.c +objects/memfile_test.o: memfile_test.c main.c vim.h protodef.h auto/config.h \ + feature.h os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h \ + option.h beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h memfile.c +objects/message_test.o: message_test.c main.c vim.h protodef.h auto/config.h \ + feature.h os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h \ + option.h beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h message.c +objects/if_lua.o: if_lua.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/if_mzsch.o: if_mzsch.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h if_mzsch.h +objects/if_perl.o: auto/if_perl.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/if_perlsfio.o: if_perlsfio.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/if_python.o: if_python.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h if_py_both.h +objects/if_python3.o: if_python3.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h if_py_both.h +objects/if_tcl.o: if_tcl.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/if_ruby.o: if_ruby.c protodef.h auto/config.h vim.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/gui_beval.o: gui_beval.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \ + beval.h proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h errors.h +objects/netbeans.o: netbeans.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h version.h +objects/job.o: job.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/channel.o: channel.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \ + globals.h errors.h +objects/gui_gtk_gresources.o: auto/gui_gtk_gresources.c +objects/vterm_encoding.o: libvterm/src/encoding.c libvterm/src/vterm_internal.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \ + libvterm/src/encoding/DECdrawing.inc libvterm/src/encoding/uk.inc +objects/vterm_keyboard.o: libvterm/src/keyboard.c libvterm/src/vterm_internal.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \ + libvterm/src/utf8.h +objects/vterm_mouse.o: libvterm/src/mouse.c libvterm/src/vterm_internal.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \ + libvterm/src/utf8.h +objects/vterm_parser.o: libvterm/src/parser.c libvterm/src/vterm_internal.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h +objects/vterm_pen.o: libvterm/src/pen.c libvterm/src/vterm_internal.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h +objects/vterm_screen.o: libvterm/src/screen.c libvterm/src/vterm_internal.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \ + libvterm/src/rect.h libvterm/src/utf8.h +objects/vterm_state.o: libvterm/src/state.c libvterm/src/vterm_internal.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h +objects/vterm_unicode.o: libvterm/src/unicode.c libvterm/src/vterm_internal.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \ + libvterm/src/fullwidth.inc +objects/vterm_vterm.o: libvterm/src/vterm.c libvterm/src/vterm_internal.h \ + libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \ + libvterm/src/utf8.h +objects/xdiffi.o: xdiff/xdiffi.c xdiff/xinclude.h auto/config.h \ + xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \ + auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h \ + termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h \ + errors.h xdiff/xtypes.h xdiff/xutils.h xdiff/xprepare.h \ + xdiff/xdiffi.h xdiff/xemit.h +objects/xemit.o: xdiff/xemit.c xdiff/xinclude.h auto/config.h \ + xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \ + auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h \ + termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h \ + errors.h xdiff/xtypes.h xdiff/xutils.h xdiff/xprepare.h \ + xdiff/xdiffi.h xdiff/xemit.h +objects/xprepare.o: xdiff/xprepare.c xdiff/xinclude.h auto/config.h \ + xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \ + auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h \ + termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h \ + errors.h xdiff/xtypes.h xdiff/xutils.h xdiff/xprepare.h \ + xdiff/xdiffi.h xdiff/xemit.h +objects/xutils.o: xdiff/xutils.c xdiff/xinclude.h auto/config.h \ + xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \ + auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h \ + termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h \ + errors.h xdiff/xtypes.h xdiff/xutils.h xdiff/xprepare.h \ + xdiff/xdiffi.h xdiff/xemit.h +objects/xhistogram.o: xdiff/xhistogram.c xdiff/xinclude.h auto/config.h \ + xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \ + auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h \ + termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h \ + errors.h xdiff/xtypes.h xdiff/xutils.h xdiff/xprepare.h \ + xdiff/xdiffi.h xdiff/xemit.h +objects/xpatience.o: xdiff/xpatience.c xdiff/xinclude.h auto/config.h \ + xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \ + auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h \ + termdefs.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h \ + libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h alloc.h \ + ex_cmds.h spell.h proto.h globals.h \ + errors.h xdiff/xtypes.h xdiff/xutils.h xdiff/xprepare.h \ + xdiff/xdiffi.h xdiff/xemit.h diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..30d5731 --- /dev/null +++ b/src/README.md @@ -0,0 +1,235 @@ +![Vim Logo](https://github.com/vim/vim/blob/master/runtime/vimlogo.gif) + +# Vim source code # + +Here are a few hints for finding your way around the source code. This +doesn't make it less complex than it is, but it gets you started. + +You might also want to read +[`:help development`](http://vimdoc.sourceforge.net/htmldoc/develop.html#development). + + +## Jumping around ## + +First of all, use `:make tags` to generate a tags file, so that you can jump +around in the source code. + +To jump to a function or variable definition, move the cursor on the name and +use the `CTRL-]` command. Use `CTRL-T` or `CTRL-O` to jump back. + +To jump to a file, move the cursor on its name and use the `gf` command. + +Most code can be found in a file with an obvious name (incomplete list): + +File name | Description +--------------- | ----------- +alloc.c | memory management +arglist.c | handling argument list +autocmd.c | autocommands +blob.c | blob data type +buffer.c | manipulating buffers (loaded files) +bufwrite.c | writing a buffer to file +change.c | handling changes to text +cindent.c | C and Lisp indentation +clientserver.c | client server functionality +clipboard.c | handling the clipboard +cmdexpand.c | command-line completion +cmdhist.c | command-line history +debugger.c | vim script debugger +diff.c | diff mode (vimdiff) +drawline.c | drawing a window line +drawscreen.c | drawing the windows +eval.c | expression evaluation +evalbuffer.c | buffer related built-in functions +evalfunc.c | built-in functions +evalvars.c | vim variables +evalwindow.c | window related built-in functions +fileio.c | reading and writing files +filepath.c | dealing with file names and paths +findfile.c | search for files in 'path' +fold.c | folding +getchar.c | getting characters and key mapping +help.c | vim help related functions +highlight.c | syntax highlighting +indent.c | text indentation +insexpand.c | Insert mode completion +locale.c | locale/language handling +map.c | mapping and abbreviations +mark.c | marks +match.c | highlight matching +float.c | floating point functions +mbyte.c | multi-byte character handling +memfile.c | storing lines for buffers in a swapfile +memline.c | storing lines for buffers in memory +menu.c | menus +message.c | (error) messages +mouse.c | handling the mouse +ops.c | handling operators ("d", "y", "p") +option.c | options +optionstr.c | handling string options +popupmenu.c | popup menu +popupwin.c | popup window +profiler.c | vim script profiler +quickfix.c | quickfix commands (":make", ":cn") +regexp.c | pattern matching +register.c | handling registers +scriptfile.c | runtime directory handling and sourcing scripts +screen.c | lower level screen functions +search.c | pattern searching +session.c | sessions and views +sign.c | signs +spell.c | spell checking core +spellfile.c | spell file handling +spellsuggest.c | spell correction suggestions +strings.c | string manipulation functions +syntax.c | syntax and other highlighting +tag.c | tags +term.c | terminal handling, termcap codes +testing.c | testing: assert and test functions +textformat.c | text formatting +textobject.c | text objects +textprop.c | text properties +time.c | time and timer functions +typval.c | vim script type/value functions +undo.c | undo and redo +usercmd.c | user defined commands +userfunc.c | user defined functions +viminfo.c | viminfo handling +window.c | handling split windows + + +## Debugging ## + +If you have a reasonable recent version of gdb, you can use the `:Termdebug` +command to debug Vim. See `:help :Termdebug`. + +When something is time critical or stepping through code is a hassle, use the +channel logging to create a time-stamped log file. Add lines to the code like +this: + + ch_log(NULL, "Value is now %02x", value); + +After compiling and starting Vim, do: + + :call ch_logfile('debuglog', 'w') + +And edit `debuglog` to see what happens. The channel functions already have +`ch_log()` calls, thus you always see that in the log. + + +## Important Variables ## + +The current mode is stored in `State`. The values it can have are `NORMAL`, +`INSERT`, `CMDLINE`, and a few others. + +The current window is `curwin`. The current buffer is `curbuf`. These point +to structures with the cursor position in the window, option values, the file +name, etc. These are defined in +[`structs.h`](https://github.com/vim/vim/blob/master/src/structs.h). + +All the global variables are declared in +[`globals.h`](https://github.com/vim/vim/blob/master/src/globals.h). + + +## The main loop ## + +This is conveniently called `main_loop()`. It updates a few things and then +calls `normal_cmd()` to process a command. This returns when the command is +finished. + +The basic idea is that Vim waits for the user to type a character and +processes it until another character is needed. Thus there are several places +where Vim waits for a character to be typed. The `vgetc()` function is used +for this. It also handles mapping. + +Updating the screen is mostly postponed until a command or a sequence of +commands has finished. The work is done by `update_screen()`, which calls +`win_update()` for every window, which calls `win_line()` for every line. +See the start of +[`screen.c`](https://github.com/vim/vim/blob/master/src/screen.c) +for more explanations. + + +## Command-line mode ## + +When typing a `:`, `normal_cmd()` will call `getcmdline()` to obtain a line +with an Ex command. `getcmdline()` contains a loop that will handle each typed +character. It returns when hitting `CR` or `Esc` or some other character that +ends the command line mode. + + +## Ex commands ## + +Ex commands are handled by the function `do_cmdline()`. It does the generic +parsing of the `:` command line and calls `do_one_cmd()` for each separate +command. It also takes care of while loops. + +`do_one_cmd()` parses the range and generic arguments and puts them in the +`exarg_t` and passes it to the function that handles the command. + +The `:` commands are listed in `ex_cmds.h`. The third entry of each item is +the name of the function that handles the command. The last entry are the +flags that are used for the command. + + +## Normal mode commands ## + +The Normal mode commands are handled by the `normal_cmd()` function. It also +handles the optional count and an extra character for some commands. These +are passed in a `cmdarg_t` to the function that handles the command. + +There is a table `nv_cmds` in +[`normal.c`](https://github.com/vim/vim/blob/master/src/normal.c) +which lists the first character of every command. The second entry of each +item is the name of the function that handles the command. + + +## Insert mode commands ## + +When doing an `i` or `a` command, `normal_cmd()` will call the `edit()` +function. It contains a loop that waits for the next character and handles it. +It returns when leaving Insert mode. + + +## Options ## + +There is a list with all option names in +[`option.c`](https://github.com/vim/vim/blob/master/src/option.c), +called `options[]`. + + +## The GUI ## + +Most of the GUI code is implemented like it was a clever terminal. Typing a +character, moving a scrollbar, clicking the mouse, etc. are all translated +into events which are written in the input buffer. These are read by the +main code, just like reading from a terminal. The code for this is scattered +through [`gui.c`](https://github.com/vim/vim/blob/master/src/gui.c). +For example, `gui_send_mouse_event()` for a mouse click and `gui_menu_cb()` for +a menu action. Key hits are handled by the system-specific GUI code, which +calls `add_to_input_buf()` to send the key code. + +Updating the GUI window is done by writing codes in the output buffer, just +like writing to a terminal. When the buffer gets full or is flushed, +`gui_write()` will parse the codes and draw the appropriate items. Finally the +system-specific GUI code will be called to do the work. + + +## Debugging the GUI ## + +Remember to prevent that gvim forks and the debugger thinks Vim has exited, +add the `-f` argument. In gdb: `run -f -g`. + +When stepping through display updating code, the focus event is triggered +when going from the debugger to Vim and back. To avoid this, recompile with +some code in `gui_focus_change()` disabled. + + +## Contributing ## + +If you would like to help making Vim better, see the +[`CONTRIBUTING.md`](https://github.com/vim/vim/blob/master/CONTRIBUTING.md) +file. + + +This is `README.md` for version 9.0 of the Vim source code. diff --git a/src/alloc.c b/src/alloc.c new file mode 100644 index 0000000..e3e6d04 --- /dev/null +++ b/src/alloc.c @@ -0,0 +1,894 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * alloc.c: functions for memory management + */ + +#include "vim.h" + +/********************************************************************** + * Various routines dealing with allocation and deallocation of memory. + */ + +#if defined(MEM_PROFILE) || defined(PROTO) + +# define MEM_SIZES 8200 +static long_u mem_allocs[MEM_SIZES]; +static long_u mem_frees[MEM_SIZES]; +static long_u mem_allocated; +static long_u mem_freed; +static long_u mem_peak; +static long_u num_alloc; +static long_u num_freed; + + static void +mem_pre_alloc_s(size_t *sizep) +{ + *sizep += sizeof(size_t); +} + + static void +mem_pre_alloc_l(size_t *sizep) +{ + *sizep += sizeof(size_t); +} + + static void +mem_post_alloc( + void **pp, + size_t size) +{ + if (*pp == NULL) + return; + size -= sizeof(size_t); + *(long_u *)*pp = size; + if (size <= MEM_SIZES-1) + mem_allocs[size-1]++; + else + mem_allocs[MEM_SIZES-1]++; + mem_allocated += size; + if (mem_allocated - mem_freed > mem_peak) + mem_peak = mem_allocated - mem_freed; + num_alloc++; + *pp = (void *)((char *)*pp + sizeof(size_t)); +} + + static void +mem_pre_free(void **pp) +{ + long_u size; + + *pp = (void *)((char *)*pp - sizeof(size_t)); + size = *(size_t *)*pp; + if (size <= MEM_SIZES-1) + mem_frees[size-1]++; + else + mem_frees[MEM_SIZES-1]++; + mem_freed += size; + num_freed++; +} + +/* + * called on exit via atexit() + */ + void +vim_mem_profile_dump(void) +{ + int i, j; + + printf("\r\n"); + j = 0; + for (i = 0; i < MEM_SIZES - 1; i++) + { + if (mem_allocs[i] == 0 && mem_frees[i] == 0) + continue; + + if (mem_frees[i] > mem_allocs[i]) + printf("\r\n%s", _("ERROR: ")); + printf("[%4d / %4lu-%-4lu] ", i + 1, mem_allocs[i], mem_frees[i]); + j++; + if (j > 3) + { + j = 0; + printf("\r\n"); + } + } + + i = MEM_SIZES - 1; + if (mem_allocs[i]) + { + printf("\r\n"); + if (mem_frees[i] > mem_allocs[i]) + puts(_("ERROR: ")); + printf("[>%d / %4lu-%-4lu]", i, mem_allocs[i], mem_frees[i]); + } + + printf(_("\n[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"), + mem_allocated, mem_freed, mem_allocated - mem_freed, mem_peak); + printf(_("[calls] total re/malloc()'s %lu, total free()'s %lu\n\n"), + num_alloc, num_freed); +} + +#endif // MEM_PROFILE + +#ifdef FEAT_EVAL + int +alloc_does_fail(size_t size) +{ + if (alloc_fail_countdown == 0) + { + if (--alloc_fail_repeat <= 0) + alloc_fail_id = 0; + do_outofmem_msg(size); + return TRUE; + } + --alloc_fail_countdown; + return FALSE; +} +#endif + +/* + * Some memory is reserved for error messages and for being able to + * call mf_release_all(), which needs some memory for mf_trans_add(). + */ +#define KEEP_ROOM (2 * 8192L) +#define KEEP_ROOM_KB (KEEP_ROOM / 1024L) + +/* + * The normal way to allocate memory. This handles an out-of-memory situation + * as well as possible, still returns NULL when we're completely out. + */ + void * +alloc(size_t size) +{ + return lalloc(size, TRUE); +} + +#if defined(FEAT_QUICKFIX) || defined(PROTO) +/* + * alloc() with an ID for alloc_fail(). + */ + void * +alloc_id(size_t size, alloc_id_T id UNUSED) +{ +# ifdef FEAT_EVAL + if (alloc_fail_id == id && alloc_does_fail(size)) + return NULL; +# endif + return lalloc(size, TRUE); +} +#endif + +/* + * Allocate memory and set all bytes to zero. + */ + void * +alloc_clear(size_t size) +{ + void *p; + + p = lalloc(size, TRUE); + if (p != NULL) + (void)vim_memset(p, 0, size); + return p; +} + +/* + * Same as alloc_clear() but with allocation id for testing + */ + void * +alloc_clear_id(size_t size, alloc_id_T id UNUSED) +{ +#ifdef FEAT_EVAL + if (alloc_fail_id == id && alloc_does_fail(size)) + return NULL; +#endif + return alloc_clear(size); +} + +/* + * Allocate memory like lalloc() and set all bytes to zero. + */ + void * +lalloc_clear(size_t size, int message) +{ + void *p; + + p = lalloc(size, message); + if (p != NULL) + (void)vim_memset(p, 0, size); + return p; +} + +/* + * Low level memory allocation function. + * This is used often, KEEP IT FAST! + */ + void * +lalloc(size_t size, int message) +{ + void *p; // pointer to new storage space + static int releasing = FALSE; // don't do mf_release_all() recursive + int try_again; +#if defined(HAVE_AVAIL_MEM) + static size_t allocated = 0; // allocated since last avail check +#endif + + // Safety check for allocating zero bytes + if (size == 0) + { + // Don't hide this message + emsg_silent = 0; + iemsg(_(e_internal_error_lalloc_zero)); + return NULL; + } + +#ifdef MEM_PROFILE + mem_pre_alloc_l(&size); +#endif + + // Loop when out of memory: Try to release some memfile blocks and + // if some blocks are released call malloc again. + for (;;) + { + // Handle three kinds of systems: + // 1. No check for available memory: Just return. + // 2. Slow check for available memory: call mch_avail_mem() after + // allocating KEEP_ROOM amount of memory. + // 3. Strict check for available memory: call mch_avail_mem() + if ((p = malloc(size)) != NULL) + { +#ifndef HAVE_AVAIL_MEM + // 1. No check for available memory: Just return. + goto theend; +#else + // 2. Slow check for available memory: call mch_avail_mem() after + // allocating (KEEP_ROOM / 2) amount of memory. + allocated += size; + if (allocated < KEEP_ROOM / 2) + goto theend; + allocated = 0; + + // 3. check for available memory: call mch_avail_mem() + if (mch_avail_mem(TRUE) < KEEP_ROOM_KB && !releasing) + { + free(p); // System is low... no go! + p = NULL; + } + else + goto theend; +#endif + } + // Remember that mf_release_all() is being called to avoid an endless + // loop, because mf_release_all() may call alloc() recursively. + if (releasing) + break; + releasing = TRUE; + + clear_sb_text(TRUE); // free any scrollback text + try_again = mf_release_all(); // release as many blocks as possible + + releasing = FALSE; + if (!try_again) + break; + } + + if (message && p == NULL) + do_outofmem_msg(size); + +theend: +#ifdef MEM_PROFILE + mem_post_alloc(&p, size); +#endif + return p; +} + +/* + * lalloc() with an ID for alloc_fail(). + */ +#if defined(FEAT_SIGNS) || defined(PROTO) + void * +lalloc_id(size_t size, int message, alloc_id_T id UNUSED) +{ +#ifdef FEAT_EVAL + if (alloc_fail_id == id && alloc_does_fail(size)) + return NULL; +#endif + return (lalloc(size, message)); +} +#endif + +#if defined(MEM_PROFILE) || defined(PROTO) +/* + * realloc() with memory profiling. + */ + void * +mem_realloc(void *ptr, size_t size) +{ + void *p; + + mem_pre_free(&ptr); + mem_pre_alloc_s(&size); + + p = realloc(ptr, size); + + mem_post_alloc(&p, size); + + return p; +} +#endif + +/* +* Avoid repeating the error message many times (they take 1 second each). +* Did_outofmem_msg is reset when a character is read. +*/ + void +do_outofmem_msg(size_t size) +{ + if (did_outofmem_msg) + return; + + // Don't hide this message + emsg_silent = 0; + + // Must come first to avoid coming back here when printing the error + // message fails, e.g. when setting v:errmsg. + did_outofmem_msg = TRUE; + + semsg(_(e_out_of_memory_allocating_nr_bytes), (long_u)size); + + if (starting == NO_SCREEN) + // Not even finished with initializations and already out of + // memory? Then nothing is going to work, exit. + mch_exit(123); +} + +#if defined(EXITFREE) || defined(PROTO) + +/* + * Free everything that we allocated. + * Can be used to detect memory leaks, e.g., with ccmalloc. + * NOTE: This is tricky! Things are freed that functions depend on. Don't be + * surprised if Vim crashes... + * Some things can't be freed, esp. things local to a library function. + */ + void +free_all_mem(void) +{ + buf_T *buf, *nextbuf; + + // When we cause a crash here it is caught and Vim tries to exit cleanly. + // Don't try freeing everything again. + if (entered_free_all_mem) + return; + entered_free_all_mem = TRUE; + // Don't want to trigger autocommands from here on. + block_autocmds(); + + // Close all tabs and windows. Reset 'equalalways' to avoid redraws. + p_ea = FALSE; + if (first_tabpage != NULL && first_tabpage->tp_next != NULL) + do_cmdline_cmd((char_u *)"tabonly!"); + if (!ONE_WINDOW) + do_cmdline_cmd((char_u *)"only!"); + +# if defined(FEAT_SPELL) + // Free all spell info. + spell_free_all(); +# endif + +# if defined(FEAT_BEVAL_TERM) + ui_remove_balloon(); +# endif +# ifdef FEAT_PROP_POPUP + if (curwin != NULL) + close_all_popups(TRUE); +# endif + + // Clear user commands (before deleting buffers). + ex_comclear(NULL); + + // When exiting from mainerr_arg_missing curbuf has not been initialized, + // and not much else. + if (curbuf != NULL) + { +# ifdef FEAT_MENU + // Clear menus. + do_cmdline_cmd((char_u *)"aunmenu *"); + do_cmdline_cmd((char_u *)"tlunmenu *"); +# ifdef FEAT_MULTI_LANG + do_cmdline_cmd((char_u *)"menutranslate clear"); +# endif +# endif + // Clear mappings, abbreviations, breakpoints. + do_cmdline_cmd((char_u *)"lmapclear"); + do_cmdline_cmd((char_u *)"xmapclear"); + do_cmdline_cmd((char_u *)"mapclear"); + do_cmdline_cmd((char_u *)"mapclear!"); + do_cmdline_cmd((char_u *)"abclear"); +# if defined(FEAT_EVAL) + do_cmdline_cmd((char_u *)"breakdel *"); +# endif +# if defined(FEAT_PROFILE) + do_cmdline_cmd((char_u *)"profdel *"); +# endif +# if defined(FEAT_KEYMAP) + do_cmdline_cmd((char_u *)"set keymap="); +# endif + } + + free_titles(); + free_findfile(); + + // Obviously named calls. + free_all_autocmds(); + clear_termcodes(); + free_all_marks(); + alist_clear(&global_alist); + free_homedir(); + free_users(); + free_search_patterns(); + free_old_sub(); + free_last_insert(); + free_insexpand_stuff(); + free_prev_shellcmd(); + free_regexp_stuff(); + free_tag_stuff(); + free_xim_stuff(); + free_cd_dir(); +# ifdef FEAT_SIGNS + free_signs(); +# endif +# ifdef FEAT_EVAL + set_expr_line(NULL, NULL); +# endif +# ifdef FEAT_DIFF + if (curtab != NULL) + diff_clear(curtab); +# endif + clear_sb_text(TRUE); // free any scrollback text + + // Free some global vars. + free_username(); +# ifdef FEAT_CLIPBOARD + vim_regfree(clip_exclude_prog); +# endif + vim_free(last_cmdline); + vim_free(new_last_cmdline); + set_keep_msg(NULL, 0); + + // Clear cmdline history. + p_hi = 0; + init_history(); +# ifdef FEAT_PROP_POPUP + clear_global_prop_types(); +# endif + +# ifdef FEAT_QUICKFIX + free_quickfix(); +# endif + + // Close all script inputs. + close_all_scripts(); + + if (curwin != NULL) + // Destroy all windows. Must come before freeing buffers. + win_free_all(); + + // Free all option values. Must come after closing windows. + free_all_options(); + + // Free all buffers. Reset 'autochdir' to avoid accessing things that + // were freed already. +# ifdef FEAT_AUTOCHDIR + p_acd = FALSE; +# endif + for (buf = firstbuf; buf != NULL; ) + { + bufref_T bufref; + + set_bufref(&bufref, buf); + nextbuf = buf->b_next; + close_buffer(NULL, buf, DOBUF_WIPE, FALSE, FALSE); + if (bufref_valid(&bufref)) + buf = nextbuf; // didn't work, try next one + else + buf = firstbuf; + } + +# ifdef FEAT_ARABIC + free_arshape_buf(); +# endif + + // Clear registers. + clear_registers(); + ResetRedobuff(); + ResetRedobuff(); + +# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) + vim_free(serverDelayedStartName); +# endif + + // highlight info + free_highlight(); + + reset_last_sourcing(); + + if (first_tabpage != NULL) + { + free_tabpage(first_tabpage); + first_tabpage = NULL; + } + +# ifdef UNIX + // Machine-specific free. + mch_free_mem(); +# endif + + // message history + for (;;) + if (delete_first_msg() == FAIL) + break; + +# ifdef FEAT_JOB_CHANNEL + channel_free_all(); +# endif +# ifdef FEAT_TIMERS + timer_free_all(); +# endif +# ifdef FEAT_EVAL + // must be after channel_free_all() with unrefs partials + eval_clear(); +# endif +# ifdef FEAT_JOB_CHANNEL + // must be after eval_clear() with unrefs jobs + job_free_all(); +# endif + + free_termoptions(); + free_cur_term(); + + // screenlines (can't display anything now!) + free_screenlines(); + +# if defined(FEAT_SOUND) + sound_free(); +# endif +# if defined(USE_XSMP) + xsmp_close(); +# endif +# ifdef FEAT_GUI_GTK + gui_mch_free_all(); +# endif +# ifdef FEAT_TCL + vim_tcl_finalize(); +# endif + clear_hl_tables(); + + vim_free(IObuff); + vim_free(NameBuff); +# ifdef FEAT_QUICKFIX + check_quickfix_busy(); +# endif +# ifdef FEAT_EVAL + free_resub_eval_result(); +# endif +} +#endif + +/* + * Copy "p[len]" into allocated memory, ignoring NUL characters. + * Returns NULL when out of memory. + */ + char_u * +vim_memsave(char_u *p, size_t len) +{ + char_u *ret = alloc(len); + + if (ret != NULL) + mch_memmove(ret, p, len); + return ret; +} + +/* + * Replacement for free() that ignores NULL pointers. + * Also skip free() when exiting for sure, this helps when we caught a deadly + * signal that was caused by a crash in free(). + * If you want to set NULL after calling this function, you should use + * VIM_CLEAR() instead. + */ + void +vim_free(void *x) +{ + if (x != NULL && !really_exiting) + { +#ifdef MEM_PROFILE + mem_pre_free(&x); +#endif + free(x); + } +} + +/************************************************************************ + * Functions for handling growing arrays. + */ + +/* + * Clear an allocated growing array. + */ + void +ga_clear(garray_T *gap) +{ + vim_free(gap->ga_data); + ga_init(gap); +} + +/* + * Clear a growing array that contains a list of strings. + */ + void +ga_clear_strings(garray_T *gap) +{ + int i; + + if (gap->ga_data != NULL) + for (i = 0; i < gap->ga_len; ++i) + vim_free(((char_u **)(gap->ga_data))[i]); + ga_clear(gap); +} + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Copy a growing array that contains a list of strings. + */ + int +ga_copy_strings(garray_T *from, garray_T *to) +{ + int i; + + ga_init2(to, sizeof(char_u *), 1); + if (ga_grow(to, from->ga_len) == FAIL) + return FAIL; + + for (i = 0; i < from->ga_len; ++i) + { + char_u *orig = ((char_u **)from->ga_data)[i]; + char_u *copy; + + if (orig == NULL) + copy = NULL; + else + { + copy = vim_strsave(orig); + if (copy == NULL) + { + to->ga_len = i; + ga_clear_strings(to); + return FAIL; + } + } + ((char_u **)to->ga_data)[i] = copy; + } + to->ga_len = from->ga_len; + return OK; +} +#endif + +/* + * Initialize a growing array. Don't forget to set ga_itemsize and + * ga_growsize! Or use ga_init2(). + */ + void +ga_init(garray_T *gap) +{ + gap->ga_data = NULL; + gap->ga_maxlen = 0; + gap->ga_len = 0; +} + + void +ga_init2(garray_T *gap, size_t itemsize, int growsize) +{ + ga_init(gap); + gap->ga_itemsize = (int)itemsize; + gap->ga_growsize = growsize; +} + +/* + * Make room in growing array "gap" for at least "n" items. + * Return FAIL for failure, OK otherwise. + */ + int +ga_grow(garray_T *gap, int n) +{ + if (gap->ga_maxlen - gap->ga_len < n) + return ga_grow_inner(gap, n); + return OK; +} + +/* + * Same as ga_grow() but uses an allocation id for testing. + */ + int +ga_grow_id(garray_T *gap, int n, alloc_id_T id UNUSED) +{ +#ifdef FEAT_EVAL + if (alloc_fail_id == id && alloc_does_fail(sizeof(list_T))) + return FAIL; +#endif + + return ga_grow(gap, n); +} + + int +ga_grow_inner(garray_T *gap, int n) +{ + size_t old_len; + size_t new_len; + char_u *pp; + + if (n < gap->ga_growsize) + n = gap->ga_growsize; + + // A linear growth is very inefficient when the array grows big. This + // is a compromise between allocating memory that won't be used and too + // many copy operations. A factor of 1.5 seems reasonable. + if (n < gap->ga_len / 2) + n = gap->ga_len / 2; + + new_len = (size_t)gap->ga_itemsize * (gap->ga_len + n); + pp = vim_realloc(gap->ga_data, new_len); + if (pp == NULL) + return FAIL; + old_len = (size_t)gap->ga_itemsize * gap->ga_maxlen; + vim_memset(pp + old_len, 0, new_len - old_len); + gap->ga_maxlen = gap->ga_len + n; + gap->ga_data = pp; + return OK; +} + +/* + * For a growing array that contains a list of strings: concatenate all the + * strings with a separating "sep". + * Returns NULL when out of memory. + */ + char_u * +ga_concat_strings(garray_T *gap, char *sep) +{ + int i; + int len = 0; + int sep_len = (int)STRLEN(sep); + char_u *s; + char_u *p; + + for (i = 0; i < gap->ga_len; ++i) + len += (int)STRLEN(((char_u **)(gap->ga_data))[i]) + sep_len; + + s = alloc(len + 1); + if (s == NULL) + return NULL; + + *s = NUL; + p = s; + for (i = 0; i < gap->ga_len; ++i) + { + if (p != s) + { + STRCPY(p, sep); + p += sep_len; + } + STRCPY(p, ((char_u **)(gap->ga_data))[i]); + p += STRLEN(p); + } + return s; +} + +/* + * Make a copy of string "p" and add it to "gap". + * When out of memory nothing changes and FAIL is returned. + */ + int +ga_copy_string(garray_T *gap, char_u *p) +{ + char_u *cp = vim_strsave(p); + + if (cp == NULL) + return FAIL; + + if (ga_grow(gap, 1) == FAIL) + { + vim_free(cp); + return FAIL; + } + ((char_u **)(gap->ga_data))[gap->ga_len++] = cp; + return OK; +} + +/* + * Add string "p" to "gap". + * When out of memory FAIL is returned (caller may want to free "p"). + */ + int +ga_add_string(garray_T *gap, char_u *p) +{ + if (ga_grow(gap, 1) == FAIL) + return FAIL; + ((char_u **)(gap->ga_data))[gap->ga_len++] = p; + return OK; +} + +/* + * Concatenate a string to a growarray which contains bytes. + * When "s" is NULL memory allocation fails does not do anything. + * Note: Does NOT copy the NUL at the end! + */ + void +ga_concat(garray_T *gap, char_u *s) +{ + int len; + + if (s == NULL || *s == NUL) + return; + len = (int)STRLEN(s); + if (ga_grow(gap, len) == OK) + { + mch_memmove((char *)gap->ga_data + gap->ga_len, s, (size_t)len); + gap->ga_len += len; + } +} + +/* + * Concatenate 'len' bytes from string 's' to a growarray. + * When "s" is NULL does not do anything. + */ + void +ga_concat_len(garray_T *gap, char_u *s, size_t len) +{ + if (s == NULL || *s == NUL || len == 0) + return; + if (ga_grow(gap, (int)len) == OK) + { + mch_memmove((char *)gap->ga_data + gap->ga_len, s, len); + gap->ga_len += (int)len; + } +} + +/* + * Append one byte to a growarray which contains bytes. + */ + int +ga_append(garray_T *gap, int c) +{ + if (ga_grow(gap, 1) == FAIL) + return FAIL; + *((char *)gap->ga_data + gap->ga_len) = c; + ++gap->ga_len; + return OK; +} + +#if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(MSWIN) \ + || defined(PROTO) +/* + * Append the text in "gap" below the cursor line and clear "gap". + */ + void +append_ga_line(garray_T *gap) +{ + // Remove trailing CR. + if (gap->ga_len > 0 + && !curbuf->b_p_bin + && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR) + --gap->ga_len; + ga_append(gap, NUL); + ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE); + gap->ga_len = 0; +} +#endif + diff --git a/src/alloc.h b/src/alloc.h new file mode 100644 index 0000000..651e01f --- /dev/null +++ b/src/alloc.h @@ -0,0 +1,49 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * alloc.h: enumeration of alloc IDs. + * Used by test_alloc_fail() to test memory allocation failures. + * Each entry must be on exactly one line, GetAllocId() depends on that. + */ +typedef enum { + aid_none = 0, + aid_qf_dirname_start, + aid_qf_dirname_now, + aid_qf_namebuf, + aid_qf_module, + aid_qf_errmsg, + aid_qf_pattern, + aid_qf_efm_fmtstr, + aid_qf_efm_fmtpart, + aid_qf_title, + aid_qf_mef_name, + aid_qf_qfline, + aid_qf_qfinfo, + aid_qf_dirstack, + aid_qf_multiline_pfx, + aid_qf_makecmd, + aid_qf_linebuf, + aid_tagstack_items, + aid_tagstack_from, + aid_tagstack_details, + aid_sign_getdefined, + aid_sign_getplaced, + aid_sign_define_by_name, + aid_sign_getlist, + aid_sign_getplaced_dict, + aid_sign_getplaced_list, + aid_insert_sign, + aid_sign_getinfo, + aid_newbuf_bvars, + aid_newwin_wvars, + aid_newtabpage_tvars, + aid_blob_alloc, + aid_get_func, + aid_last +} alloc_id_T; diff --git a/src/arabic.c b/src/arabic.c new file mode 100644 index 0000000..f64dab2 --- /dev/null +++ b/src/arabic.c @@ -0,0 +1,396 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * arabic.c: functions for Arabic language + * + * Author: Nadim Shaikli & Isam Bayazidi + * Farsi support and restructuring to make adding new letters easier by Ali + * Gholami Rudi. Further work by Ameretat Reith. + */ + +/* + * Sorted list of unicode Arabic characters. Each entry holds the + * presentation forms of a letter. + * + * Arabic characters are categorized into following types: + * + * Isolated - iso-8859-6 form + * Initial - unicode form-B start + * Medial - unicode form-B middle + * Final - unicode form-B final + * Stand-Alone - unicode form-B isolated + */ + +#include "vim.h" + +#if defined(FEAT_ARABIC) || defined(PROTO) + +// Unicode values for Arabic characters. +#define a_HAMZA 0x0621 +#define a_ALEF_MADDA 0x0622 +#define a_ALEF_HAMZA_ABOVE 0x0623 +#define a_WAW_HAMZA 0x0624 +#define a_ALEF_HAMZA_BELOW 0x0625 +#define a_YEH_HAMZA 0x0626 +#define a_ALEF 0x0627 +#define a_BEH 0x0628 +#define a_TEH_MARBUTA 0x0629 +#define a_TEH 0x062a +#define a_THEH 0x062b +#define a_JEEM 0x062c +#define a_HAH 0x062d +#define a_KHAH 0x062e +#define a_DAL 0x062f +#define a_THAL 0x0630 +#define a_REH 0x0631 +#define a_ZAIN 0x0632 +#define a_SEEN 0x0633 +#define a_SHEEN 0x0634 +#define a_SAD 0x0635 +#define a_DAD 0x0636 +#define a_TAH 0x0637 +#define a_ZAH 0x0638 +#define a_AIN 0x0639 +#define a_GHAIN 0x063a +#define a_TATWEEL 0x0640 +#define a_FEH 0x0641 +#define a_QAF 0x0642 +#define a_KAF 0x0643 +#define a_LAM 0x0644 +#define a_MEEM 0x0645 +#define a_NOON 0x0646 +#define a_HEH 0x0647 +#define a_WAW 0x0648 +#define a_ALEF_MAKSURA 0x0649 +#define a_YEH 0x064a +#define a_FATHATAN 0x064b +#define a_DAMMATAN 0x064c +#define a_KASRATAN 0x064d +#define a_FATHA 0x064e +#define a_DAMMA 0x064f +#define a_KASRA 0x0650 +#define a_SHADDA 0x0651 +#define a_SUKUN 0x0652 +#define a_MADDA_ABOVE 0x0653 +#define a_HAMZA_ABOVE 0x0654 +#define a_HAMZA_BELOW 0x0655 + +#define a_PEH 0x067e +#define a_TCHEH 0x0686 +#define a_JEH 0x0698 +#define a_FKAF 0x06a9 +#define a_GAF 0x06af +#define a_FYEH 0x06cc + +#define a_s_LAM_ALEF_MADDA_ABOVE 0xfef5 +#define a_f_LAM_ALEF_MADDA_ABOVE 0xfef6 +#define a_s_LAM_ALEF_HAMZA_ABOVE 0xfef7 +#define a_f_LAM_ALEF_HAMZA_ABOVE 0xfef8 +#define a_s_LAM_ALEF_HAMZA_BELOW 0xfef9 +#define a_f_LAM_ALEF_HAMZA_BELOW 0xfefa +#define a_s_LAM_ALEF 0xfefb +#define a_f_LAM_ALEF 0xfefc + +static struct achar { + unsigned c; + unsigned isolated; + unsigned initial; + unsigned medial; + unsigned final; +} achars[] = { + {a_HAMZA, 0xfe80, 0, 0, 0}, + {a_ALEF_MADDA, 0xfe81, 0, 0, 0xfe82}, + {a_ALEF_HAMZA_ABOVE, 0xfe83, 0, 0, 0xfe84}, + {a_WAW_HAMZA, 0xfe85, 0, 0, 0xfe86}, + {a_ALEF_HAMZA_BELOW, 0xfe87, 0, 0, 0xfe88}, + {a_YEH_HAMZA, 0xfe89, 0xfe8b, 0xfe8c, 0xfe8a}, + {a_ALEF, 0xfe8d, 0, 0, 0xfe8e}, + {a_BEH, 0xfe8f, 0xfe91, 0xfe92, 0xfe90}, + {a_TEH_MARBUTA, 0xfe93, 0, 0, 0xfe94}, + {a_TEH, 0xfe95, 0xfe97, 0xfe98, 0xfe96}, + {a_THEH, 0xfe99, 0xfe9b, 0xfe9c, 0xfe9a}, + {a_JEEM, 0xfe9d, 0xfe9f, 0xfea0, 0xfe9e}, + {a_HAH, 0xfea1, 0xfea3, 0xfea4, 0xfea2}, + {a_KHAH, 0xfea5, 0xfea7, 0xfea8, 0xfea6}, + {a_DAL, 0xfea9, 0, 0, 0xfeaa}, + {a_THAL, 0xfeab, 0, 0, 0xfeac}, + {a_REH, 0xfead, 0, 0, 0xfeae}, + {a_ZAIN, 0xfeaf, 0, 0, 0xfeb0}, + {a_SEEN, 0xfeb1, 0xfeb3, 0xfeb4, 0xfeb2}, + {a_SHEEN, 0xfeb5, 0xfeb7, 0xfeb8, 0xfeb6}, + {a_SAD, 0xfeb9, 0xfebb, 0xfebc, 0xfeba}, + {a_DAD, 0xfebd, 0xfebf, 0xfec0, 0xfebe}, + {a_TAH, 0xfec1, 0xfec3, 0xfec4, 0xfec2}, + {a_ZAH, 0xfec5, 0xfec7, 0xfec8, 0xfec6}, + {a_AIN, 0xfec9, 0xfecb, 0xfecc, 0xfeca}, + {a_GHAIN, 0xfecd, 0xfecf, 0xfed0, 0xfece}, + {a_TATWEEL, 0, 0x0640, 0x0640, 0x0640}, + {a_FEH, 0xfed1, 0xfed3, 0xfed4, 0xfed2}, + {a_QAF, 0xfed5, 0xfed7, 0xfed8, 0xfed6}, + {a_KAF, 0xfed9, 0xfedb, 0xfedc, 0xfeda}, + {a_LAM, 0xfedd, 0xfedf, 0xfee0, 0xfede}, + {a_MEEM, 0xfee1, 0xfee3, 0xfee4, 0xfee2}, + {a_NOON, 0xfee5, 0xfee7, 0xfee8, 0xfee6}, + {a_HEH, 0xfee9, 0xfeeb, 0xfeec, 0xfeea}, + {a_WAW, 0xfeed, 0, 0, 0xfeee}, + {a_ALEF_MAKSURA, 0xfeef, 0, 0, 0xfef0}, + {a_YEH, 0xfef1, 0xfef3, 0xfef4, 0xfef2}, + {a_FATHATAN, 0xfe70, 0, 0, 0}, + {a_DAMMATAN, 0xfe72, 0, 0, 0}, + {a_KASRATAN, 0xfe74, 0, 0, 0}, + {a_FATHA, 0xfe76, 0, 0xfe77, 0}, + {a_DAMMA, 0xfe78, 0, 0xfe79, 0}, + {a_KASRA, 0xfe7a, 0, 0xfe7b, 0}, + {a_SHADDA, 0xfe7c, 0, 0xfe7c, 0}, + {a_SUKUN, 0xfe7e, 0, 0xfe7f, 0}, + {a_MADDA_ABOVE, 0, 0, 0, 0}, + {a_HAMZA_ABOVE, 0, 0, 0, 0}, + {a_HAMZA_BELOW, 0, 0, 0, 0}, + {a_PEH, 0xfb56, 0xfb58, 0xfb59, 0xfb57}, + {a_TCHEH, 0xfb7a, 0xfb7c, 0xfb7d, 0xfb7b}, + {a_JEH, 0xfb8a, 0, 0, 0xfb8b}, + {a_FKAF, 0xfb8e, 0xfb90, 0xfb91, 0xfb8f}, + {a_GAF, 0xfb92, 0xfb94, 0xfb95, 0xfb93}, + {a_FYEH, 0xfbfc, 0xfbfe, 0xfbff, 0xfbfd}, +}; + +#define a_BYTE_ORDER_MARK 0xfeff + +/* + * Find the struct achar pointer to the given Arabic char. + * Returns NULL if not found. + */ + static struct achar * +find_achar(int c) +{ + int h, m, l; + + // using binary search to find c + h = ARRAY_LENGTH(achars); + l = 0; + while (l < h) + { + m = (h + l) / 2; + if (achars[m].c == (unsigned)c) + return &achars[m]; + if ((unsigned)c < achars[m].c) + h = m; + else + l = m + 1; + } + return NULL; +} + +/* + * Change shape - from Combination (2 char) to an Isolated + */ + static int +chg_c_laa2i(int hid_c) +{ + int tempc; + + switch (hid_c) + { + case a_ALEF_MADDA: + tempc = a_s_LAM_ALEF_MADDA_ABOVE; + break; + case a_ALEF_HAMZA_ABOVE: + tempc = a_s_LAM_ALEF_HAMZA_ABOVE; + break; + case a_ALEF_HAMZA_BELOW: + tempc = a_s_LAM_ALEF_HAMZA_BELOW; + break; + case a_ALEF: + tempc = a_s_LAM_ALEF; + break; + default: + tempc = 0; + } + + return tempc; +} + +/* + * Change shape - from Combination-Isolated to Final + */ + static int +chg_c_laa2f(int hid_c) +{ + int tempc; + + switch (hid_c) + { + case a_ALEF_MADDA: + tempc = a_f_LAM_ALEF_MADDA_ABOVE; + break; + case a_ALEF_HAMZA_ABOVE: + tempc = a_f_LAM_ALEF_HAMZA_ABOVE; + break; + case a_ALEF_HAMZA_BELOW: + tempc = a_f_LAM_ALEF_HAMZA_BELOW; + break; + case a_ALEF: + tempc = a_f_LAM_ALEF; + break; + default: + tempc = 0; + } + + return tempc; +} + +/* + * Returns whether it is possible to join the given letters + */ + static int +can_join(int c1, int c2) +{ + struct achar *a1 = find_achar(c1); + struct achar *a2 = find_achar(c2); + + return a1 && a2 && (a1->initial || a1->medial) && (a2->final || a2->medial); +} + +/* + * Check whether we are dealing with a character that could be regarded as an + * Arabic combining character, need to check the character before this. + */ + int +arabic_maycombine(int two) +{ + if (p_arshape && !p_tbidi) + return (two == a_ALEF_MADDA + || two == a_ALEF_HAMZA_ABOVE + || two == a_ALEF_HAMZA_BELOW + || two == a_ALEF); + return FALSE; +} + +/* + * Check whether we are dealing with Arabic combining characters. + * Note: these are NOT really composing characters! + */ + int +arabic_combine( + int one, // first character + int two) // character just after "one" +{ + if (one == a_LAM) + return arabic_maycombine(two); + return FALSE; +} + +/* + * A_is_iso returns true if 'c' is an Arabic ISO-8859-6 character + * (alphabet/number/punctuation) + */ + static int +A_is_iso(int c) +{ + return find_achar(c) != NULL; +} + +/* + * A_is_ok returns true if 'c' is an Arabic 10646 (8859-6 or Form-B) + */ + static int +A_is_ok(int c) +{ + return (A_is_iso(c) || c == a_BYTE_ORDER_MARK); +} + +/* + * A_is_valid returns true if 'c' is an Arabic 10646 (8859-6 or Form-B) + * with some exceptions/exclusions + */ + static int +A_is_valid(int c) +{ + return (A_is_ok(c) && c != a_HAMZA); +} + +/* + * Do Arabic shaping on character "c". Returns the shaped character. + * out: "ccp" points to the first byte of the character to be shaped. + * in/out: "c1p" points to the first composing char for "c". + * in: "prev_c" is the previous character (not shaped) + * in: "prev_c1" is the first composing char for the previous char + * (not shaped) + * in: "next_c" is the next character (not shaped). + */ + int +arabic_shape( + int c, + int *ccp, + int *c1p, + int prev_c, + int prev_c1, + int next_c) +{ + int curr_c; + int curr_laa; + int prev_laa; + + // Deal only with Arabic characters, pass back all others + if (!A_is_ok(c)) + return c; + + curr_laa = arabic_combine(c, *c1p); + prev_laa = arabic_combine(prev_c, prev_c1); + + if (curr_laa) + { + if (A_is_valid(prev_c) && can_join(prev_c, a_LAM) && !prev_laa) + curr_c = chg_c_laa2f(*c1p); + else + curr_c = chg_c_laa2i(*c1p); + + // Remove the composing character + *c1p = 0; + } + else + { + struct achar *curr_a = find_achar(c); + int backward_combine = !prev_laa && can_join(prev_c, c); + int forward_combine = can_join(c, next_c); + + if (backward_combine) + { + if (forward_combine) + curr_c = curr_a->medial; + else + curr_c = curr_a->final; + } + else + { + if (forward_combine) + curr_c = curr_a->initial; + else + curr_c = curr_a->isolated; + } + } + + // Character missing from the table means using original character. + if (curr_c == NUL) + curr_c = c; + + if (curr_c != c && ccp != NULL) + { + char_u buf[MB_MAXBYTES + 1]; + + // Update the first byte of the character. + (*mb_char2bytes)(curr_c, buf); + *ccp = buf[0]; + } + + // Return the shaped character + return curr_c; +} +#endif // FEAT_ARABIC diff --git a/src/arglist.c b/src/arglist.c new file mode 100644 index 0000000..bb31c45 --- /dev/null +++ b/src/arglist.c @@ -0,0 +1,1496 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * arglist.c: functions for dealing with the argument list + */ + +#include "vim.h" + +#define AL_SET 1 +#define AL_ADD 2 +#define AL_DEL 3 + +// This flag is set whenever the argument list is being changed and calling a +// function that might trigger an autocommand. +static int arglist_locked = FALSE; + + static int +check_arglist_locked(void) +{ + if (arglist_locked) + { + emsg(_(e_cannot_change_arglist_recursively)); + return FAIL; + } + return OK; +} + +/* + * Clear an argument list: free all file names and reset it to zero entries. + */ + void +alist_clear(alist_T *al) +{ + if (check_arglist_locked() == FAIL) + return; + while (--al->al_ga.ga_len >= 0) + vim_free(AARGLIST(al)[al->al_ga.ga_len].ae_fname); + ga_clear(&al->al_ga); +} + +/* + * Init an argument list. + */ + void +alist_init(alist_T *al) +{ + ga_init2(&al->al_ga, sizeof(aentry_T), 5); +} + +/* + * Remove a reference from an argument list. + * Ignored when the argument list is the global one. + * If the argument list is no longer used by any window, free it. + */ + void +alist_unlink(alist_T *al) +{ + if (al != &global_alist && --al->al_refcount <= 0) + { + alist_clear(al); + vim_free(al); + } +} + +/* + * Create a new argument list and use it for the current window. + */ + void +alist_new(void) +{ + curwin->w_alist = ALLOC_ONE(alist_T); + if (curwin->w_alist == NULL) + { + curwin->w_alist = &global_alist; + ++global_alist.al_refcount; + } + else + { + curwin->w_alist->al_refcount = 1; + curwin->w_alist->id = ++max_alist_id; + alist_init(curwin->w_alist); + } +} + +#if !defined(UNIX) || defined(PROTO) +/* + * Expand the file names in the global argument list. + * If "fnum_list" is not NULL, use "fnum_list[fnum_len]" as a list of buffer + * numbers to be re-used. + */ + void +alist_expand(int *fnum_list, int fnum_len) +{ + char_u **old_arg_files; + int old_arg_count; + char_u **new_arg_files; + int new_arg_file_count; + char_u *save_p_su = p_su; + int i; + + old_arg_files = ALLOC_MULT(char_u *, GARGCOUNT); + if (old_arg_files == NULL) + return; + + // Don't use 'suffixes' here. This should work like the shell did the + // expansion. Also, the vimrc file isn't read yet, thus the user + // can't set the options. + p_su = empty_option; + for (i = 0; i < GARGCOUNT; ++i) + old_arg_files[i] = vim_strsave(GARGLIST[i].ae_fname); + old_arg_count = GARGCOUNT; + if (expand_wildcards(old_arg_count, old_arg_files, + &new_arg_file_count, &new_arg_files, + EW_FILE|EW_NOTFOUND|EW_ADDSLASH|EW_NOERROR) == OK + && new_arg_file_count > 0) + { + alist_set(&global_alist, new_arg_file_count, new_arg_files, + TRUE, fnum_list, fnum_len); + FreeWild(old_arg_count, old_arg_files); + } + p_su = save_p_su; +} +#endif + +/* + * Set the argument list for the current window. + * Takes over the allocated files[] and the allocated fnames in it. + */ + void +alist_set( + alist_T *al, + int count, + char_u **files, + int use_curbuf, + int *fnum_list, + int fnum_len) +{ + int i; + + if (check_arglist_locked() == FAIL) + return; + + alist_clear(al); + if (GA_GROW_OK(&al->al_ga, count)) + { + for (i = 0; i < count; ++i) + { + if (got_int) + { + // When adding many buffers this can take a long time. Allow + // interrupting here. + while (i < count) + vim_free(files[i++]); + break; + } + + // May set buffer name of a buffer previously used for the + // argument list, so that it's re-used by alist_add. + if (fnum_list != NULL && i < fnum_len) + { + arglist_locked = TRUE; + buf_set_name(fnum_list[i], files[i]); + arglist_locked = FALSE; + } + + alist_add(al, files[i], use_curbuf ? 2 : 1); + ui_breakcheck(); + } + vim_free(files); + } + else + FreeWild(count, files); + if (al == &global_alist) + arg_had_last = FALSE; +} + +/* + * Add file "fname" to argument list "al". + * "fname" must have been allocated and "al" must have been checked for room. + */ + void +alist_add( + alist_T *al, + char_u *fname, + int set_fnum) // 1: set buffer number; 2: re-use curbuf +{ + if (fname == NULL) // don't add NULL file names + return; + if (check_arglist_locked() == FAIL) + return; + arglist_locked = TRUE; + +#ifdef BACKSLASH_IN_FILENAME + slash_adjust(fname); +#endif + AARGLIST(al)[al->al_ga.ga_len].ae_fname = fname; + if (set_fnum > 0) + AARGLIST(al)[al->al_ga.ga_len].ae_fnum = + buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0)); + ++al->al_ga.ga_len; + + arglist_locked = FALSE; +} + +#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) +/* + * Adjust slashes in file names. Called after 'shellslash' was set. + */ + void +alist_slash_adjust(void) +{ + int i; + win_T *wp; + tabpage_T *tp; + + for (i = 0; i < GARGCOUNT; ++i) + if (GARGLIST[i].ae_fname != NULL) + slash_adjust(GARGLIST[i].ae_fname); + FOR_ALL_TAB_WINDOWS(tp, wp) + if (wp->w_alist != &global_alist) + for (i = 0; i < WARGCOUNT(wp); ++i) + if (WARGLIST(wp)[i].ae_fname != NULL) + slash_adjust(WARGLIST(wp)[i].ae_fname); +} +#endif + +/* + * Isolate one argument, taking backticks. + * Changes the argument in-place, puts a NUL after it. Backticks remain. + * Return a pointer to the start of the next argument. + */ + static char_u * +do_one_arg(char_u *str) +{ + char_u *p; + int inbacktick; + + inbacktick = FALSE; + for (p = str; *str; ++str) + { + // When the backslash is used for escaping the special meaning of a + // character we need to keep it until wildcard expansion. + if (rem_backslash(str)) + { + *p++ = *str++; + *p++ = *str; + } + else + { + // An item ends at a space not in backticks + if (!inbacktick && vim_isspace(*str)) + break; + if (*str == '`') + inbacktick ^= TRUE; + *p++ = *str; + } + } + str = skipwhite(str); + *p = NUL; + + return str; +} + +/* + * Separate the arguments in "str" and return a list of pointers in the + * growarray "gap". + */ + static int +get_arglist(garray_T *gap, char_u *str, int escaped) +{ + ga_init2(gap, sizeof(char_u *), 20); + while (*str != NUL) + { + if (ga_grow(gap, 1) == FAIL) + { + ga_clear(gap); + return FAIL; + } + ((char_u **)gap->ga_data)[gap->ga_len++] = str; + + // If str is escaped, don't handle backslashes or spaces + if (!escaped) + return OK; + + // Isolate one argument, change it in-place, put a NUL after it. + str = do_one_arg(str); + } + return OK; +} + +#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(FEAT_SPELL) || defined(PROTO) +/* + * Parse a list of arguments (file names), expand them and return in + * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'. + * Return FAIL or OK. + */ + int +get_arglist_exp( + char_u *str, + int *fcountp, + char_u ***fnamesp, + int wig) +{ + garray_T ga; + int i; + + if (get_arglist(&ga, str, TRUE) == FAIL) + return FAIL; + if (wig == TRUE) + i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data, + fcountp, fnamesp, EW_FILE|EW_NOTFOUND|EW_NOTWILD); + else + i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data, + fcountp, fnamesp, EW_FILE|EW_NOTFOUND|EW_NOTWILD); + + ga_clear(&ga); + return i; +} +#endif + +/* + * Check the validity of the arg_idx for each other window. + */ + static void +alist_check_arg_idx(void) +{ + win_T *win; + tabpage_T *tp; + + FOR_ALL_TAB_WINDOWS(tp, win) + if (win->w_alist == curwin->w_alist) + check_arg_idx(win); +} + +/* + * Add files[count] to the arglist of the current window after arg "after". + * The file names in files[count] must have been allocated and are taken over. + * Files[] itself is not taken over. + */ + static void +alist_add_list( + int count, + char_u **files, + int after, // where to add: 0 = before first one + int will_edit) // will edit adding argument +{ + int i; + int old_argcount = ARGCOUNT; + + if (check_arglist_locked() != FAIL + && GA_GROW_OK(&ALIST(curwin)->al_ga, count)) + { + if (after < 0) + after = 0; + if (after > ARGCOUNT) + after = ARGCOUNT; + if (after < ARGCOUNT) + mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), + (ARGCOUNT - after) * sizeof(aentry_T)); + arglist_locked = TRUE; + for (i = 0; i < count; ++i) + { + int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0); + + ARGLIST[after + i].ae_fname = files[i]; + ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags); + } + arglist_locked = FALSE; + ALIST(curwin)->al_ga.ga_len += count; + if (old_argcount > 0 && curwin->w_arg_idx >= after) + curwin->w_arg_idx += count; + return; + } + + for (i = 0; i < count; ++i) + vim_free(files[i]); +} + +/* + * Delete the file names in 'alist_ga' from the argument list. + */ + static void +arglist_del_files(garray_T *alist_ga) +{ + regmatch_T regmatch; + int didone; + int i; + char_u *p; + int match; + + // Delete the items: use each item as a regexp and find a match in the + // argument list. + regmatch.rm_ic = p_fic; // ignore case when 'fileignorecase' is set + for (i = 0; i < alist_ga->ga_len && !got_int; ++i) + { + p = ((char_u **)alist_ga->ga_data)[i]; + p = file_pat_to_reg_pat(p, NULL, NULL, FALSE); + if (p == NULL) + break; + regmatch.regprog = vim_regcomp(p, magic_isset() ? RE_MAGIC : 0); + if (regmatch.regprog == NULL) + { + vim_free(p); + break; + } + + didone = FALSE; + for (match = 0; match < ARGCOUNT; ++match) + if (vim_regexec(®match, alist_name(&ARGLIST[match]), (colnr_T)0)) + { + didone = TRUE; + vim_free(ARGLIST[match].ae_fname); + mch_memmove(ARGLIST + match, ARGLIST + match + 1, + (ARGCOUNT - match - 1) * sizeof(aentry_T)); + --ALIST(curwin)->al_ga.ga_len; + if (curwin->w_arg_idx > match) + --curwin->w_arg_idx; + --match; + } + + vim_regfree(regmatch.regprog); + vim_free(p); + if (!didone) + semsg(_(e_no_match_str_2), ((char_u **)alist_ga->ga_data)[i]); + } + ga_clear(alist_ga); +} + +/* + * "what" == AL_SET: Redefine the argument list to 'str'. + * "what" == AL_ADD: add files in 'str' to the argument list after "after". + * "what" == AL_DEL: remove files in 'str' from the argument list. + * + * Return FAIL for failure, OK otherwise. + */ + static int +do_arglist( + char_u *str, + int what, + int after UNUSED, // 0 means before first one + int will_edit) // will edit added argument +{ + garray_T new_ga; + int exp_count; + char_u **exp_files; + int i; + int arg_escaped = TRUE; + + if (check_arglist_locked() == FAIL) + return FAIL; + + // Set default argument for ":argadd" command. + if (what == AL_ADD && *str == NUL) + { + if (curbuf->b_ffname == NULL) + return FAIL; + str = curbuf->b_fname; + arg_escaped = FALSE; + } + + // Collect all file name arguments in "new_ga". + if (get_arglist(&new_ga, str, arg_escaped) == FAIL) + return FAIL; + + if (what == AL_DEL) + arglist_del_files(&new_ga); + else + { + i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data, + &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND); + ga_clear(&new_ga); + if (i == FAIL || exp_count == 0) + { + emsg(_(e_no_match)); + return FAIL; + } + + if (what == AL_ADD) + { + alist_add_list(exp_count, exp_files, after, will_edit); + vim_free(exp_files); + } + else // what == AL_SET + alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0); + } + + alist_check_arg_idx(); + + return OK; +} + +/* + * Redefine the argument list. + */ + void +set_arglist(char_u *str) +{ + do_arglist(str, AL_SET, 0, FALSE); +} + +/* + * Return TRUE if window "win" is editing the file at the current argument + * index. + */ + int +editing_arg_idx(win_T *win) +{ + return !(win->w_arg_idx >= WARGCOUNT(win) + || (win->w_buffer->b_fnum + != WARGLIST(win)[win->w_arg_idx].ae_fnum + && (win->w_buffer->b_ffname == NULL + || !(fullpathcmp( + alist_name(&WARGLIST(win)[win->w_arg_idx]), + win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME)))); +} + +/* + * Check if window "win" is editing the w_arg_idx file in its argument list. + */ + void +check_arg_idx(win_T *win) +{ + if (WARGCOUNT(win) > 1 && !editing_arg_idx(win)) + { + // We are not editing the current entry in the argument list. + // Set "arg_had_last" if we are editing the last one. + win->w_arg_idx_invalid = TRUE; + if (win->w_arg_idx != WARGCOUNT(win) - 1 + && arg_had_last == FALSE + && ALIST(win) == &global_alist + && GARGCOUNT > 0 + && win->w_arg_idx < GARGCOUNT + && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum + || (win->w_buffer->b_ffname != NULL + && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]), + win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME)))) + arg_had_last = TRUE; + } + else + { + // We are editing the current entry in the argument list. + // Set "arg_had_last" if it's also the last one + win->w_arg_idx_invalid = FALSE; + if (win->w_arg_idx == WARGCOUNT(win) - 1 + && win->w_alist == &global_alist) + arg_had_last = TRUE; + } +} + +/* + * ":args", ":argslocal" and ":argsglobal". + */ + void +ex_args(exarg_T *eap) +{ + int i; + + if (eap->cmdidx != CMD_args) + { + if (check_arglist_locked() == FAIL) + return; + alist_unlink(ALIST(curwin)); + if (eap->cmdidx == CMD_argglobal) + ALIST(curwin) = &global_alist; + else // eap->cmdidx == CMD_arglocal + alist_new(); + } + + // ":args file ..": define new argument list, handle like ":next" + // Also for ":argslocal file .." and ":argsglobal file ..". + if (*eap->arg != NUL) + { + if (check_arglist_locked() == FAIL) + return; + ex_next(eap); + return; + } + + // ":args": list arguments. + if (eap->cmdidx == CMD_args) + { + char_u **items; + + if (ARGCOUNT <= 0) + return; // empty argument list + + items = ALLOC_MULT(char_u *, ARGCOUNT); + if (items == NULL) + return; + + // Overwrite the command, for a short list there is no scrolling + // required and no wait_return(). + gotocmdline(TRUE); + + for (i = 0; i < ARGCOUNT; ++i) + items[i] = alist_name(&ARGLIST[i]); + list_in_columns(items, ARGCOUNT, curwin->w_arg_idx); + vim_free(items); + + return; + } + + // ":argslocal": make a local copy of the global argument list. + if (eap->cmdidx == CMD_arglocal) + { + garray_T *gap = &curwin->w_alist->al_ga; + + if (GA_GROW_FAILS(gap, GARGCOUNT)) + return; + + for (i = 0; i < GARGCOUNT; ++i) + if (GARGLIST[i].ae_fname != NULL) + { + AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname = + vim_strsave(GARGLIST[i].ae_fname); + AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum = + GARGLIST[i].ae_fnum; + ++gap->ga_len; + } + } +} + +/* + * ":previous", ":sprevious", ":Next" and ":sNext". + */ + void +ex_previous(exarg_T *eap) +{ + // If past the last one already, go to the last one. + if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT) + do_argfile(eap, ARGCOUNT - 1); + else + do_argfile(eap, curwin->w_arg_idx - (int)eap->line2); +} + +/* + * ":rewind", ":first", ":sfirst" and ":srewind". + */ + void +ex_rewind(exarg_T *eap) +{ + do_argfile(eap, 0); +} + +/* + * ":last" and ":slast". + */ + void +ex_last(exarg_T *eap) +{ + do_argfile(eap, ARGCOUNT - 1); +} + +/* + * ":argument" and ":sargument". + */ + void +ex_argument(exarg_T *eap) +{ + int i; + + if (eap->addr_count > 0) + i = eap->line2 - 1; + else + i = curwin->w_arg_idx; + do_argfile(eap, i); +} + +/* + * Edit file "argn" of the argument lists. + */ + void +do_argfile(exarg_T *eap, int argn) +{ + int other; + char_u *p; + int old_arg_idx = curwin->w_arg_idx; + + if (ERROR_IF_ANY_POPUP_WINDOW) + return; + if (argn < 0 || argn >= ARGCOUNT) + { + if (ARGCOUNT <= 1) + emsg(_(e_there_is_only_one_file_to_edit)); + else if (argn < 0) + emsg(_(e_cannot_go_before_first_file)); + else + emsg(_(e_cannot_go_beyond_last_file)); + + return; + } + + setpcmark(); +#ifdef FEAT_GUI + need_mouse_correct = TRUE; +#endif + + // split window or create new tab page first + if (*eap->cmd == 's' || cmdmod.cmod_tab != 0) + { + if (win_split(0, 0) == FAIL) + return; + RESET_BINDING(curwin); + } + else + { + // if 'hidden' set, only check for changed file when re-editing + // the same buffer + other = TRUE; + if (buf_hide(curbuf)) + { + p = fix_fname(alist_name(&ARGLIST[argn])); + other = otherfile(p); + vim_free(p); + } + if ((!buf_hide(curbuf) || !other) + && check_changed(curbuf, CCGD_AW + | (other ? 0 : CCGD_MULTWIN) + | (eap->forceit ? CCGD_FORCEIT : 0) + | CCGD_EXCMD)) + return; + } + + curwin->w_arg_idx = argn; + if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist) + arg_had_last = TRUE; + + // Edit the file; always use the last known line number. + // When it fails (e.g. Abort for already edited file) restore the + // argument index. + if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL, + eap, ECMD_LAST, + (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0) + + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) + curwin->w_arg_idx = old_arg_idx; + // like Vi: set the mark where the cursor is in the file. + else if (eap->cmdidx != CMD_argdo) + setmark('\''); +} + +/* + * ":next", and commands that behave like it. + */ + void +ex_next(exarg_T *eap) +{ + int i; + + // check for changed buffer now, if this fails the argument list is not + // redefined. + if ( buf_hide(curbuf) + || eap->cmdidx == CMD_snext + || !check_changed(curbuf, CCGD_AW + | (eap->forceit ? CCGD_FORCEIT : 0) + | CCGD_EXCMD)) + { + if (*eap->arg != NUL) // redefine file list + { + if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL) + return; + i = 0; + } + else + i = curwin->w_arg_idx + (int)eap->line2; + do_argfile(eap, i); + } +} + +/* + * ":argdedupe" + */ + void +ex_argdedupe(exarg_T *eap UNUSED) +{ + int i; + int j; + + for (i = 0; i < ARGCOUNT; ++i) + { + // Expand each argument to a full path to catch different paths leading + // to the same file. + char_u *firstFullname = FullName_save(ARGLIST[i].ae_fname, FALSE); + if (firstFullname == NULL) + return; // out of memory + + for (j = i + 1; j < ARGCOUNT; ++j) + { + char_u *secondFullname = FullName_save(ARGLIST[j].ae_fname, FALSE); + if (secondFullname == NULL) + break; // out of memory + int areNamesDuplicate = + fnamecmp(firstFullname, secondFullname) == 0; + vim_free(secondFullname); + + if (areNamesDuplicate) + { + // remove one duplicate argument + vim_free(ARGLIST[j].ae_fname); + mch_memmove(ARGLIST + j, ARGLIST + j + 1, + (ARGCOUNT - j - 1) * sizeof(aentry_T)); + --ARGCOUNT; + + if (curwin->w_arg_idx == j) + curwin->w_arg_idx = i; + else if (curwin->w_arg_idx > j) + --curwin->w_arg_idx; + + --j; + } + } + + vim_free(firstFullname); + } +} + +/* + * ":argedit" + */ + void +ex_argedit(exarg_T *eap) +{ + int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1; + // Whether curbuf will be reused, curbuf->b_ffname will be set. + int curbuf_is_reusable = curbuf_reusable(); + + if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL) + return; + maketitle(); + + if (curwin->w_arg_idx == 0 + && (curbuf->b_ml.ml_flags & ML_EMPTY) + && (curbuf->b_ffname == NULL || curbuf_is_reusable)) + i = 0; + // Edit the argument. + if (i < ARGCOUNT) + do_argfile(eap, i); +} + +/* + * ":argadd" + */ + void +ex_argadd(exarg_T *eap) +{ + do_arglist(eap->arg, AL_ADD, + eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1, + FALSE); + maketitle(); +} + +/* + * ":argdelete" + */ + void +ex_argdelete(exarg_T *eap) +{ + int i; + int n; + + if (check_arglist_locked() == FAIL) + return; + + if (eap->addr_count > 0 || *eap->arg == NUL) + { + // ":argdel" works like ":.argdel" + if (eap->addr_count == 0) + { + if (curwin->w_arg_idx >= ARGCOUNT) + { + emsg(_(e_no_argument_to_delete)); + return; + } + eap->line1 = eap->line2 = curwin->w_arg_idx + 1; + } + else if (eap->line2 > ARGCOUNT) + // ":1,4argdel": Delete all arguments in the range. + eap->line2 = ARGCOUNT; + n = eap->line2 - eap->line1 + 1; + if (*eap->arg != NUL) + // Can't have both a range and an argument. + emsg(_(e_invalid_argument)); + else if (n <= 0) + { + // Don't give an error for ":%argdel" if the list is empty. + if (eap->line1 != 1 || eap->line2 != 0) + emsg(_(e_invalid_range)); + } + else + { + for (i = eap->line1; i <= eap->line2; ++i) + vim_free(ARGLIST[i - 1].ae_fname); + mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2, + (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T))); + ALIST(curwin)->al_ga.ga_len -= n; + if (curwin->w_arg_idx >= eap->line2) + curwin->w_arg_idx -= n; + else if (curwin->w_arg_idx > eap->line1) + curwin->w_arg_idx = eap->line1; + if (ARGCOUNT == 0) + curwin->w_arg_idx = 0; + else if (curwin->w_arg_idx >= ARGCOUNT) + curwin->w_arg_idx = ARGCOUNT - 1; + } + } + else + do_arglist(eap->arg, AL_DEL, 0, FALSE); + maketitle(); +} + +/* + * Function given to ExpandGeneric() to obtain the possible arguments of the + * argedit and argdelete commands. + */ + char_u * +get_arglist_name(expand_T *xp UNUSED, int idx) +{ + if (idx >= ARGCOUNT) + return NULL; + + return alist_name(&ARGLIST[idx]); +} + +/* + * Get the file name for an argument list entry. + */ + char_u * +alist_name(aentry_T *aep) +{ + buf_T *bp; + + // Use the name from the associated buffer if it exists. + bp = buflist_findnr(aep->ae_fnum); + if (bp == NULL || bp->b_fname == NULL) + return aep->ae_fname; + return bp->b_fname; +} + +/* + * State used by the :all command to open all the files in the argument list in + * separate windows. + */ +typedef struct { + alist_T *alist; // argument list to be used + int had_tab; + int keep_tabs; + int forceit; + + int use_firstwin; // use first window for arglist + char_u *opened; // Array of weight for which args are open: + // 0: not opened + // 1: opened in other tab + // 2: opened in curtab + // 3: opened in curtab and curwin + int opened_len; // length of opened[] + win_T *new_curwin; + tabpage_T *new_curtab; +} arg_all_state_T; + +/* + * Close all the windows containing files which are not in the argument list. + * Used by the ":all" command. + */ + static void +arg_all_close_unused_windows(arg_all_state_T *aall) +{ + win_T *wp; + win_T *wpnext; + tabpage_T *tpnext; + buf_T *buf; + int i; + win_T *old_curwin; + tabpage_T *old_curtab; + + old_curwin = curwin; + old_curtab = curtab; + + if (aall->had_tab > 0) + goto_tabpage_tp(first_tabpage, TRUE, TRUE); + for (;;) + { + tpnext = curtab->tp_next; + for (wp = firstwin; wp != NULL; wp = wpnext) + { + wpnext = wp->w_next; + buf = wp->w_buffer; + if (buf->b_ffname == NULL + || (!aall->keep_tabs && (buf->b_nwindows > 1 + || wp->w_width != Columns))) + i = aall->opened_len; + else + { + // check if the buffer in this window is in the arglist + for (i = 0; i < aall->opened_len; ++i) + { + if (i < aall->alist->al_ga.ga_len + && (AARGLIST(aall->alist)[i].ae_fnum == buf->b_fnum + || fullpathcmp(alist_name( + &AARGLIST(aall->alist)[i]), + buf->b_ffname, TRUE, TRUE) & FPC_SAME)) + { + int weight = 1; + + if (old_curtab == curtab) + { + ++weight; + if (old_curwin == wp) + ++weight; + } + + if (weight > (int)aall->opened[i]) + { + aall->opened[i] = (char_u)weight; + if (i == 0) + { + if (aall->new_curwin != NULL) + aall->new_curwin->w_arg_idx = + aall->opened_len; + aall->new_curwin = wp; + aall->new_curtab = curtab; + } + } + else if (aall->keep_tabs) + i = aall->opened_len; + + if (wp->w_alist != aall->alist) + { + // Use the current argument list for all windows + // containing a file from it. + alist_unlink(wp->w_alist); + wp->w_alist = aall->alist; + ++wp->w_alist->al_refcount; + } + break; + } + } + } + wp->w_arg_idx = i; + + if (i == aall->opened_len && !aall->keep_tabs)// close this window + { + if (buf_hide(buf) || aall->forceit || buf->b_nwindows > 1 + || !bufIsChanged(buf)) + { + // If the buffer was changed, and we would like to hide it, + // try autowriting. + if (!buf_hide(buf) && buf->b_nwindows <= 1 + && bufIsChanged(buf)) + { + bufref_T bufref; + + set_bufref(&bufref, buf); + + (void)autowrite(buf, FALSE); + + // check if autocommands removed the window + if (!win_valid(wp) || !bufref_valid(&bufref)) + { + wpnext = firstwin; // start all over... + continue; + } + } + // don't close last window + if (ONE_WINDOW + && (first_tabpage->tp_next == NULL + || !aall->had_tab)) + aall->use_firstwin = TRUE; + else + { + win_close(wp, !buf_hide(buf) && !bufIsChanged(buf)); + + // check if autocommands removed the next window + if (!win_valid(wpnext)) + wpnext = firstwin; // start all over... + } + } + } + } + + // Without the ":tab" modifier only do the current tab page. + if (aall->had_tab == 0 || tpnext == NULL) + break; + + // check if autocommands removed the next tab page + if (!valid_tabpage(tpnext)) + tpnext = first_tabpage; // start all over... + + goto_tabpage_tp(tpnext, TRUE, TRUE); + } +} + +/* + * Open upto "count" windows for the files in the argument list 'aall->alist'. + */ + static void +arg_all_open_windows(arg_all_state_T *aall, int count) +{ + win_T *wp; + int tab_drop_empty_window = FALSE; + int i; + int split_ret = OK; + int p_ea_save; + + // ":tab drop file" should re-use an empty window to avoid "--remote-tab" + // leaving an empty tab page when executed locally. + if (aall->keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1 + && curbuf->b_ffname == NULL && !curbuf->b_changed) + { + aall->use_firstwin = TRUE; + tab_drop_empty_window = TRUE; + } + + for (i = 0; i < count && !got_int; ++i) + { + if (aall->alist == &global_alist && i == global_alist.al_ga.ga_len - 1) + arg_had_last = TRUE; + if (aall->opened[i] > 0) + { + // Move the already present window to below the current window + if (curwin->w_arg_idx != i) + { + FOR_ALL_WINDOWS(wp) + { + if (wp->w_arg_idx == i) + { + if (aall->keep_tabs) + { + aall->new_curwin = wp; + aall->new_curtab = curtab; + } + else if (wp->w_frame->fr_parent + != curwin->w_frame->fr_parent) + { + emsg(_(e_window_layout_changed_unexpectedly)); + i = count; + break; + } + else + win_move_after(wp, curwin); + break; + } + } + } + } + else if (split_ret == OK) + { + // trigger events for tab drop + if (tab_drop_empty_window && i == count - 1) + --autocmd_no_enter; + if (!aall->use_firstwin) // split current window + { + p_ea_save = p_ea; + p_ea = TRUE; // use space from all windows + split_ret = win_split(0, WSP_ROOM | WSP_BELOW); + p_ea = p_ea_save; + if (split_ret == FAIL) + continue; + } + else // first window: do autocmd for leaving this buffer + --autocmd_no_leave; + + // edit file "i" + curwin->w_arg_idx = i; + if (i == 0) + { + aall->new_curwin = curwin; + aall->new_curtab = curtab; + } + (void)do_ecmd(0, alist_name(&AARGLIST(aall->alist)[i]), NULL, NULL, + ECMD_ONE, + ((buf_hide(curwin->w_buffer) + || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) + + ECMD_OLDBUF, curwin); + if (tab_drop_empty_window && i == count - 1) + ++autocmd_no_enter; + if (aall->use_firstwin) + ++autocmd_no_leave; + aall->use_firstwin = FALSE; + } + ui_breakcheck(); + + // When ":tab" was used open a new tab for a new window repeatedly. + if (aall->had_tab > 0 && tabpage_index(NULL) <= p_tpm) + cmdmod.cmod_tab = 9999; + } +} + +/* + * do_arg_all(): Open up to "count" windows, one for each argument. + */ + static void +do_arg_all( + int count, + int forceit, // hide buffers in current windows + int keep_tabs) // keep current tabs, for ":tab drop file" +{ + arg_all_state_T aall; + win_T *last_curwin; + tabpage_T *last_curtab; + int prev_arglist_locked = arglist_locked; + + if (cmdwin_type != 0) + { + emsg(_(e_invalid_in_cmdline_window)); + return; + } + if (ARGCOUNT <= 0) + { + // Don't give an error message. We don't want it when the ":all" + // command is in the .vimrc. + return; + } + setpcmark(); + + aall.use_firstwin = FALSE; + aall.had_tab = cmdmod.cmod_tab; + aall.new_curwin = NULL; + aall.new_curtab = NULL; + aall.forceit = forceit; + aall.keep_tabs = keep_tabs; + aall.opened_len = ARGCOUNT; + aall.opened = alloc_clear(aall.opened_len); + if (aall.opened == NULL) + return; + + // Autocommands may do anything to the argument list. Make sure it's not + // freed while we are working here by "locking" it. We still have to + // watch out for its size being changed. + aall.alist = curwin->w_alist; + ++aall.alist->al_refcount; + arglist_locked = TRUE; + +#ifdef FEAT_GUI + need_mouse_correct = TRUE; +#endif + + // Try closing all windows that are not in the argument list. + // Also close windows that are not full width; + // When 'hidden' or "forceit" set the buffer becomes hidden. + // Windows that have a changed buffer and can't be hidden won't be closed. + // When the ":tab" modifier was used do this for all tab pages. + arg_all_close_unused_windows(&aall); + + // Open a window for files in the argument list that don't have one. + // ARGCOUNT may change while doing this, because of autocommands. + if (count > aall.opened_len || count <= 0) + count = aall.opened_len; + + // Don't execute Win/Buf Enter/Leave autocommands here. + ++autocmd_no_enter; + ++autocmd_no_leave; + last_curwin = curwin; + last_curtab = curtab; + win_enter(lastwin, FALSE); + + /* + * Open upto "count" windows. + */ + arg_all_open_windows(&aall, count); + + // Remove the "lock" on the argument list. + alist_unlink(aall.alist); + arglist_locked = prev_arglist_locked; + + --autocmd_no_enter; + + // restore last referenced tabpage's curwin + if (last_curtab != aall.new_curtab) + { + if (valid_tabpage(last_curtab)) + goto_tabpage_tp(last_curtab, TRUE, TRUE); + if (win_valid(last_curwin)) + win_enter(last_curwin, FALSE); + } + // to window with first arg + if (valid_tabpage(aall.new_curtab)) + goto_tabpage_tp(aall.new_curtab, TRUE, TRUE); + if (win_valid(aall.new_curwin)) + win_enter(aall.new_curwin, FALSE); + + --autocmd_no_leave; + vim_free(aall.opened); +} + +/* + * ":all" and ":sall". + * Also used for ":tab drop file ..." after setting the argument list. + */ + void +ex_all(exarg_T *eap) +{ + if (eap->addr_count == 0) + eap->line2 = 9999; + do_arg_all((int)eap->line2, eap->forceit, eap->cmdidx == CMD_drop); +} + +/* + * Concatenate all files in the argument list, separated by spaces, and return + * it in one allocated string. + * Spaces and backslashes in the file names are escaped with a backslash. + * Returns NULL when out of memory. + */ + char_u * +arg_all(void) +{ + int len; + int idx; + char_u *retval = NULL; + char_u *p; + + // Do this loop two times: + // first time: compute the total length + // second time: concatenate the names + for (;;) + { + len = 0; + for (idx = 0; idx < ARGCOUNT; ++idx) + { + p = alist_name(&ARGLIST[idx]); + if (p == NULL) + continue; + if (len > 0) + { + // insert a space in between names + if (retval != NULL) + retval[len] = ' '; + ++len; + } + for ( ; *p != NUL; ++p) + { + if (*p == ' ' +#ifndef BACKSLASH_IN_FILENAME + || *p == '\\' +#endif + || *p == '`') + { + // insert a backslash + if (retval != NULL) + retval[len] = '\\'; + ++len; + } + if (retval != NULL) + retval[len] = *p; + ++len; + } + } + + // second time: break here + if (retval != NULL) + { + retval[len] = NUL; + break; + } + + // allocate memory + retval = alloc(len + 1); + if (retval == NULL) + break; + } + + return retval; +} + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * "argc([window id])" function + */ + void +f_argc(typval_T *argvars, typval_T *rettv) +{ + win_T *wp; + + if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL) + return; + + if (argvars[0].v_type == VAR_UNKNOWN) + // use the current window + rettv->vval.v_number = ARGCOUNT; + else if (argvars[0].v_type == VAR_NUMBER + && tv_get_number(&argvars[0]) == -1) + // use the global argument list + rettv->vval.v_number = GARGCOUNT; + else + { + // use the argument list of the specified window + wp = find_win_by_nr_or_id(&argvars[0]); + if (wp != NULL) + rettv->vval.v_number = WARGCOUNT(wp); + else + rettv->vval.v_number = -1; + } +} + +/* + * "argidx()" function + */ + void +f_argidx(typval_T *argvars UNUSED, typval_T *rettv) +{ + rettv->vval.v_number = curwin->w_arg_idx; +} + +/* + * "arglistid()" function + */ + void +f_arglistid(typval_T *argvars, typval_T *rettv) +{ + win_T *wp; + + if (in_vim9script() + && (check_for_opt_number_arg(argvars, 0) == FAIL + || (argvars[0].v_type != VAR_UNKNOWN + && check_for_opt_number_arg(argvars, 1) == FAIL))) + return; + + rettv->vval.v_number = -1; + wp = find_tabwin(&argvars[0], &argvars[1], NULL); + if (wp != NULL) + rettv->vval.v_number = wp->w_alist->id; +} + +/* + * Get the argument list for a given window + */ + static void +get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv) +{ + int idx; + + if (rettv_list_alloc(rettv) == OK && arglist != NULL) + for (idx = 0; idx < argcount; ++idx) + list_append_string(rettv->vval.v_list, + alist_name(&arglist[idx]), -1); +} + +/* + * "argv(nr)" function + */ + void +f_argv(typval_T *argvars, typval_T *rettv) +{ + int idx; + aentry_T *arglist = NULL; + int argcount = -1; + + if (in_vim9script() + && (check_for_opt_number_arg(argvars, 0) == FAIL + || (argvars[0].v_type != VAR_UNKNOWN + && check_for_opt_number_arg(argvars, 1) == FAIL))) + return; + + if (argvars[0].v_type == VAR_UNKNOWN) + { + get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv); + return; + } + + if (argvars[1].v_type == VAR_UNKNOWN) + { + arglist = ARGLIST; + argcount = ARGCOUNT; + } + else if (argvars[1].v_type == VAR_NUMBER + && tv_get_number(&argvars[1]) == -1) + { + arglist = GARGLIST; + argcount = GARGCOUNT; + } + else + { + win_T *wp = find_win_by_nr_or_id(&argvars[1]); + + if (wp != NULL) + { + // Use the argument list of the specified window + arglist = WARGLIST(wp); + argcount = WARGCOUNT(wp); + } + } + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + idx = tv_get_number_chk(&argvars[0], NULL); + if (arglist != NULL && idx >= 0 && idx < argcount) + rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx])); + else if (idx == -1) + get_arglist_as_rettv(arglist, argcount, rettv); +} +#endif diff --git a/src/ascii.h b/src/ascii.h new file mode 100644 index 0000000..ec83970 --- /dev/null +++ b/src/ascii.h @@ -0,0 +1,92 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * Definitions of various common control characters. + */ + +#define CharOrd(x) ((x) < 'a' ? (x) - 'A' : (x) - 'a') +#define CharOrdLow(x) ((x) - 'a') +#define CharOrdUp(x) ((x) - 'A') +#define ROT13(c, a) (((((c) - (a)) + 13) % 26) + (a)) + +#define NUL '\000' +#define BELL '\007' +#define BS '\010' +#define TAB '\011' +#define NL '\012' +#define NL_STR (char_u *)"\012" +#define FF '\014' +#define CAR '\015' // CR is used by Mac OS X +#define ESC '\033' +#define ESC_STR (char_u *)"\033" +#define ESC_STR_nc "\033" +#define DEL 0x7f +#define DEL_STR (char_u *)"\177" + +#define POUND 0xA3 + +#define Ctrl_chr(x) (TOUPPER_ASC(x) ^ 0x40) // '?' -> DEL, '@' -> ^@, etc. +#define Meta(x) ((x) | 0x80) + +#define CTRL_F_STR "\006" +#define CTRL_H_STR "\010" +#define CTRL_V_STR "\026" + +#define Ctrl_AT 0 // @ +#define Ctrl_A 1 +#define Ctrl_B 2 +#define Ctrl_C 3 +#define Ctrl_D 4 +#define Ctrl_E 5 +#define Ctrl_F 6 +#define Ctrl_G 7 +#define Ctrl_H 8 +#define Ctrl_I 9 +#define Ctrl_J 10 +#define Ctrl_K 11 +#define Ctrl_L 12 +#define Ctrl_M 13 +#define Ctrl_N 14 +#define Ctrl_O 15 +#define Ctrl_P 16 +#define Ctrl_Q 17 +#define Ctrl_R 18 +#define Ctrl_S 19 +#define Ctrl_T 20 +#define Ctrl_U 21 +#define Ctrl_V 22 +#define Ctrl_W 23 +#define Ctrl_X 24 +#define Ctrl_Y 25 +#define Ctrl_Z 26 + // CTRL- [ Left Square Bracket == ESC +#define Ctrl_BSL 28 // \ BackSLash +#define Ctrl_RSB 29 // ] Right Square Bracket +#define Ctrl_HAT 30 // ^ +#define Ctrl__ 31 + +#define CSI 0x9b // Control Sequence Introducer +#define CSI_STR "\233" +#define DCS 0x90 // Device Control String +#define OSC 0x9d // Operating System Command +#define STERM 0x9c // String Terminator + +/* + * Character that separates dir names in a path. + * For MS-DOS, WIN32 and OS/2 we use a backslash. A slash mostly works + * fine, but there are places where it doesn't (e.g. in a command name). + * For Acorn we use a dot. + */ +#ifdef BACKSLASH_IN_FILENAME +# define PATHSEP psepc +# define PATHSEPSTR pseps +#else +# define PATHSEP '/' +# define PATHSEPSTR "/" +#endif diff --git a/src/auto/configure b/src/auto/configure new file mode 100755 index 0000000..eddb721 --- /dev/null +++ b/src/auto/configure @@ -0,0 +1,16382 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="vim.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +LINK_AS_NEEDED +DEPEND_CFLAGS_FILTER +MSGFMT_DESKTOP +MAKEMO +MSGFMT +INSTALL_TOOL_LANGS +INSTALL_LANGS +TAGPRG +GUI_X_LIBS +GUITYPE +GUI_LIB_LOC +GUI_INC_LOC +NARROW_PROTO +MOTIF_LIBNAME +GRESOURCE_OBJ +GRESOURCE_SRC +UPDATE_DESKTOP_DATABASE +GTK_UPDATE_ICON_CACHE +GLIB_COMPILE_RESOURCES +GNOME_INCLUDEDIR +GNOME_LIBDIR +GNOME_LIBS +GTK_LIBNAME +GTK_LIBS +GTK_CFLAGS +PKG_CONFIG +X_LIB +X_EXTRA_LIBS +X_LIBS +X_PRE_LIBS +X_CFLAGS +XMKMF +xmkmfpath +TERM_TEST +TERM_OBJ +TERM_SRC +CHANNEL_OBJ +CHANNEL_SRC +NETBEANS_OBJ +NETBEANS_SRC +RUBY_LIBS +RUBY_CFLAGS_EXTRA +RUBY_CFLAGS +RUBY_PRO +RUBY_OBJ +RUBY_SRC +vi_cv_path_ruby +TCL_LIBS +TCL_CFLAGS_EXTRA +TCL_CFLAGS +TCL_PRO +TCL_OBJ +TCL_SRC +vi_cv_path_tcl +PYTHON3_OBJ +PYTHON3_SRC +PYTHON3_CFLAGS_EXTRA +PYTHON3_CFLAGS +PYTHON3_LIBS +vi_cv_path_python3 +PYTHON_OBJ +PYTHON_SRC +PYTHON_CFLAGS_EXTRA +PYTHON_CFLAGS +PYTHON_LIBS +vi_cv_path_python +PERL_LIBS +PERL_CFLAGS_EXTRA +PERL_CFLAGS +PERL_PRO +PERL_OBJ +PERL_SRC +shrpenv +vi_cv_perl_xsubpp +vi_cv_perllib +vi_cv_path_perl +MZSCHEME_MZC +MZSCHEME_EXTRA +MZSCHEME_CFLAGS +MZSCHEME_LIBS +MZSCHEME_PRO +MZSCHEME_OBJ +MZSCHEME_SRC +vi_cv_path_mzscheme +LUA_CFLAGS_EXTRA +LUA_CFLAGS +LUA_LIBS +LUA_PRO +LUA_OBJ +LUA_SRC +vi_cv_path_plain_lua +vi_cv_path_luajit +vi_cv_path_lua +XDIFF_OBJS_USED +compiledby +dogvimdiff +dovimdiff +QUOTESED +line_break +VIEWNAME +EXNAME +VIMNAME +OS_EXTRA_OBJ +OS_EXTRA_SRC +XCODE_SELECT +CPP_MM +CROSS_COMPILING +BUILD_DATE_MSG +STRIP +AWK +FGREP +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +SET_MAKE +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_fail_if_missing +enable_darwin +with_mac_arch +with_developer_dir +with_local_dir +with_vim_name +with_ex_name +with_view_name +with_global_runtime +with_modified_by +enable_smack +enable_selinux +with_features +with_compiledby +enable_xsmp +enable_xsmp_interact +enable_luainterp +with_lua_prefix +with_luajit +enable_mzschemeinterp +with_plthome +enable_perlinterp +enable_pythoninterp +with_python_command +with_python_config_dir +enable_python3interp +with_python3_command +with_python3_config_dir +enable_tclinterp +with_tclsh +enable_rubyinterp +with_ruby_command +enable_cscope +enable_netbeans +enable_channel +enable_terminal +enable_autoservername +enable_multibyte +enable_rightleft +enable_arabic +enable_farsi +enable_xim +enable_fontset +with_x +enable_gui +enable_gtk2_check +enable_gnome_check +enable_gtk3_check +enable_motif_check +enable_gtktest +with_gnome_includes +with_gnome_libs +with_gnome +enable_icon_cache_update +enable_desktop_database_update +with_motif_lib +with_tlib +enable_largefile +enable_canberra +enable_libsodium +enable_acl +enable_gpm +enable_sysmouse +enable_nls +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +XMKMF' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +X features: + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-fail-if-missing Fail if dependencies on additional features + specified on the command line are missing. + --disable-darwin Disable Darwin (Mac OS X) support. + --disable-smack Do not check for Smack support. + --disable-selinux Do not check for SELinux support. + --disable-xsmp Disable XSMP session management + --disable-xsmp-interact Disable XSMP interaction + --enable-luainterp=OPTS Include Lua interpreter. default=no OPTS=no/yes/dynamic + --enable-mzschemeinterp Include MzScheme interpreter. + --enable-perlinterp=OPTS Include Perl interpreter. default=no OPTS=no/yes/dynamic + --enable-pythoninterp=OPTS Include Python interpreter. default=no OPTS=no/yes/dynamic + --enable-python3interp=OPTS Include Python3 interpreter. default=no OPTS=no/yes/dynamic + --enable-tclinterp=OPTS Include Tcl interpreter. default=no OPTS=no/yes/dynamic + --enable-rubyinterp=OPTS Include Ruby interpreter. default=no OPTS=no/yes/dynamic + --enable-cscope Include cscope interface. + --disable-netbeans Disable NetBeans integration support. + --disable-channel Disable process communication support. + --enable-terminal Enable terminal emulation support. + --enable-autoservername Automatically define servername at vim startup. + --enable-multibyte Include multibyte editing support. + --disable-rightleft Do not include Right-to-Left language support. + --disable-arabic Do not include Arabic language support. + --disable-farsi Deprecated. + --enable-xim Include XIM input support. + --enable-fontset Include X fontset output support. + --enable-gui=OPTS X11 GUI. default=auto OPTS=auto/no/gtk2/gnome2/gtk3/motif/haiku/photon/carbon + --enable-gtk2-check If auto-select GUI, check for GTK+ 2 default=yes + --enable-gnome-check If GTK GUI, check for GNOME default=no + --enable-gtk3-check If auto-select GUI, check for GTK+ 3 default=yes + --enable-motif-check If auto-select GUI, check for Motif default=yes + --disable-gtktest Do not try to compile and run a test GTK program + --disable-icon-cache-update update disabled + --disable-desktop-database-update update disabled + --disable-largefile omit support for large files + --disable-canberra Do not use libcanberra. + --disable-libsodium Do not use libsodium. + --disable-acl No check for ACL support. + --enable-gpm=OPTS Use gpm (Linux mouse daemon). default=yes OPTS=yes/no/dynamic + --disable-sysmouse Don't use sysmouse (mouse in *BSD console). + --disable-nls Don't support NLS (gettext()). + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-mac-arch=ARCH current, intel, ppc or both + --with-developer-dir=PATH use PATH as location for Xcode developer tools + --with-local-dir=PATH search PATH instead of /usr/local for local libraries. + --without-local-dir do not search /usr/local for local libraries. + --with-vim-name=NAME what to call the Vim executable + --with-ex-name=NAME what to call the Ex executable + --with-view-name=NAME what to call the View executable + --with-global-runtime=DIR global runtime directory in 'runtimepath', comma-separated for multiple directories + --with-modified-by=NAME name of who modified a release version + --with-features=TYPE tiny, normal or huge (default: huge) + --with-compiledby=NAME name to show in :version message + --with-lua-prefix=PFX Prefix where Lua is installed. + --with-luajit Link with LuaJIT instead of Lua. + --with-plthome=PLTHOME Use PLTHOME. + --with-python-command=NAME name of the Python 2 command (default: python2 or python) + --with-python-config-dir=PATH Python's config directory (deprecated) + --with-python3-command=NAME name of the Python 3 command (default: python3 or python) + --with-python3-config-dir=PATH Python's config directory (deprecated) + --with-tclsh=PATH which tclsh to use (default: tclsh8.0) + --with-ruby-command=RUBY name of the Ruby command (default: ruby) + --with-x use the X Window System + --with-gnome-includes=DIR Specify location of GNOME headers + --with-gnome-libs=DIR Specify location of GNOME libs + --with-gnome Specify prefix for GNOME files + --with-motif-lib=STRING Library for Motif + --with-tlib=library terminal library to be used + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + XMKMF Path to xmkmf, Makefile generator for X Window System + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_c_find_uintX_t LINENO BITS VAR +# ------------------------------------ +# Finds an unsigned integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_uintX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 +$as_echo_n "checking for uint$2_t... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ + 'unsigned long long int' 'unsigned short int' 'unsigned char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + case $ac_type in #( + uint$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_find_uintX_t + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 auto/config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>auto/config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers auto/config.h:config.h.in" + + +$as_echo "#define UNIX 1" >>confdefs.h + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 +$as_echo_n "checking for $CC option to accept ISO C99... " >&6; } +if ${ac_cv_prog_cc_c99+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +#include + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +#define debug(...) fprintf (stderr, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + your preprocessor is broken; +#endif +#if BIG_OK +#else + your preprocessor is broken; +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\0'; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static void +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str; + int number; + float fnumber; + + while (*format) + { + switch (*format++) + { + case 's': // string + str = va_arg (args_copy, const char *); + break; + case 'd': // int + number = va_arg (args_copy, int); + break; + case 'f': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); +} + +int +main () +{ + + // Check bool. + _Bool success = false; + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + test_varargs ("s, d' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' + || dynamic_array[ni.number - 1] != 543); + + ; + return 0; +} +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c99" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c99" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +$as_echo "$ac_cv_prog_cc_c99" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c99" != xno; then : + +fi + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "" >/dev/null 2>&1; then : + +fi +rm -f conftest* + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 +$as_echo_n "checking for library containing strerror... " >&6; } +if ${ac_cv_search_strerror+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char strerror (); +int +main () +{ +return strerror (); + ; + return 0; +} +_ACEOF +for ac_lib in '' cposix; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_strerror=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_strerror+:} false; then : + break +fi +done +if ${ac_cv_search_strerror+:} false; then : + +else + ac_cv_search_strerror=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5 +$as_echo "$ac_cv_search_strerror" >&6; } +ac_res=$ac_cv_search_strerror +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +# Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_STRIP" && ac_cv_prog_STRIP=":" +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 +$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } +if ${ac_cv_header_sys_wait_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +int +main () +{ + int s; + wait (&s); + s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_sys_wait_h=yes +else + ac_cv_header_sys_wait_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 +$as_echo "$ac_cv_header_sys_wait_h" >&6; } +if test $ac_cv_header_sys_wait_h = yes; then + +$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h + +fi + + +if test x"$ac_cv_prog_cc_c99" != xno; then + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned long long int" >&5 +$as_echo_n "checking for unsigned long long int... " >&6; } +if ${ac_cv_type_unsigned_long_long_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_type_unsigned_long_long_int=yes + if test "x${ac_cv_prog_cc_c99-no}" = xno; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + /* For now, do not test the preprocessor; as of 2007 there are too many + implementations with broken preprocessors. Perhaps this can + be revisited in 2012. In the meantime, code should not expect + #if to work with literals wider than 32 bits. */ + /* Test literals. */ + long long int ll = 9223372036854775807ll; + long long int nll = -9223372036854775807LL; + unsigned long long int ull = 18446744073709551615ULL; + /* Test constant expressions. */ + typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll) + ? 1 : -1)]; + typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1 + ? 1 : -1)]; + int i = 63; +int +main () +{ +/* Test availability of runtime routines for shift and division. */ + long long int llmax = 9223372036854775807ll; + unsigned long long int ullmax = 18446744073709551615ull; + return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) + | (llmax / ll) | (llmax % ll) + | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i) + | (ullmax / ull) | (ullmax % ull)); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +else + ac_cv_type_unsigned_long_long_int=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_unsigned_long_long_int" >&5 +$as_echo "$ac_cv_type_unsigned_long_long_int" >&6; } + if test $ac_cv_type_unsigned_long_long_int = yes; then + +$as_echo "#define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long int" >&5 +$as_echo_n "checking for long long int... " >&6; } +if ${ac_cv_type_long_long_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_type_long_long_int=yes + if test "x${ac_cv_prog_cc_c99-no}" = xno; then + ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int + if test $ac_cv_type_long_long_int = yes; then + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifndef LLONG_MAX + # define HALF \ + (1LL << (sizeof (long long int) * CHAR_BIT - 2)) + # define LLONG_MAX (HALF - 1 + HALF) + #endif +int +main () +{ +long long int n = 1; + int i; + for (i = 0; ; i++) + { + long long int m = n << i; + if (m >> i != n) + return 1; + if (LLONG_MAX / 2 < m) + break; + } + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_type_long_long_int=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_long_int" >&5 +$as_echo "$ac_cv_type_long_long_int" >&6; } + if test $ac_cv_type_long_long_int = yes; then + +$as_echo "#define HAVE_LONG_LONG_INT 1" >>confdefs.h + + fi + + if test "$ac_cv_type_long_long_int" = no; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Compiler does not support long long int +See \`config.log' for more details" "$LINENO" 5; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler supports trailing commas" >&5 +$as_echo_n "checking if the compiler supports trailing commas... " >&6; } + trailing_commas=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + enum { + one, + }; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; trailing_commas=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$trailing_commas" = no; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Compiler does not support trailing comma in enum +See \`config.log' for more details" "$LINENO" 5; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler supports C++ comments" >&5 +$as_echo_n "checking if the compiler supports C++ comments... " >&6; } + slash_comments=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +// C++ comments? + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; slash_comments=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$slash_comments" = no; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Compiler does not support C++ comments +See \`config.log' for more details" "$LINENO" 5; } + fi +fi + +if test -n "$SOURCE_DATE_EPOCH"; then + DATE_FMT="%b %d %Y %H:%M:%S" + BUILD_DATE=$(LC_ALL=C date -u -d "@$SOURCE_DATE_EPOCH" "+$DATE_FMT" 2>/dev/null || LC_ALL=C date -u -r "$SOURCE_DATE_EPOCH" "+$DATE_FMT" 2>/dev/null || LC_ALL=C date -u "+$DATE_FMT") + cat >>confdefs.h <<_ACEOF +#define BUILD_DATE "$BUILD_DATE" +_ACEOF + + BUILD_DATE_MSG=-"echo -e '=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\nNOTE: build date/time is fixed: $BUILD_DATE\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-='" + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-fail-if-missing argument" >&5 +$as_echo_n "checking --enable-fail-if-missing argument... " >&6; } +# Check whether --enable-fail_if_missing was given. +if test "${enable_fail_if_missing+set}" = set; then : + enableval=$enable_fail_if_missing; fail_if_missing="yes" +else + fail_if_missing="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $fail_if_missing" >&5 +$as_echo "$fail_if_missing" >&6; } + +with_x_arg="$with_x" + +if test -z "$CFLAGS"; then + CFLAGS="-O" + test "$GCC" = yes && CFLAGS="-O2 -fno-strength-reduce -Wall -Wno-deprecated-declarations" +fi +if test "$GCC" = yes; then + gccversion=`$CC -dumpversion` + if test "x$gccversion" = "x"; then + gccversion=`$CC --version | sed -e '2,$d' -e 's/darwin.//' -e 's/^[^0-9]*\([0-9]\.[0-9.]*\).*$/\1/g'` + fi + if test "$gccversion" = "3.0.1" -o "$gccversion" = "3.0.2" -o "$gccversion" = "4.0.1"; then + echo 'GCC [34].0.[12] has a bug in the optimizer, disabling "-O#"' + CFLAGS=`echo "$CFLAGS" | sed 's/-O[23456789]/-O/'` + else + if test "$gccversion" = "3.1" -o "$gccversion" = "3.2" -o "$gccversion" = "3.2.1" && `echo "$CFLAGS" | grep -v fno-strength-reduce >/dev/null`; then + echo 'GCC 3.1 and 3.2 have a bug in the optimizer, adding "-fno-strength-reduce"' + CFLAGS="$CFLAGS -fno-strength-reduce" + fi + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clang version" >&5 +$as_echo_n "checking for clang version... " >&6; } +CLANG_VERSION_STRING=`$CC --version 2>/dev/null | sed -n -e 's/^.*clang[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$/\1/p'` +if test x"$CLANG_VERSION_STRING" != x"" ; then + CLANG_MAJOR=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*/\1/p'` + CLANG_MINOR=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*/\1/p'` + CLANG_REVISION=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\)/\1/p'` + CLANG_VERSION=`expr $CLANG_MAJOR '*' 1000000 '+' $CLANG_MINOR '*' 1000 '+' $CLANG_REVISION` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CLANG_VERSION" >&5 +$as_echo "$CLANG_VERSION" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if clang supports -fno-strength-reduce" >&5 +$as_echo_n "checking if clang supports -fno-strength-reduce... " >&6; } + if test "$CLANG_MAJOR" -ge 10 -o "$CLANG_VERSION" -ge 500002075 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS=`echo "$CFLAGS" | sed -e 's/-fno-strength-reduce/ /'` + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: N/A" >&5 +$as_echo "N/A" >&6; } +fi + +CROSS_COMPILING= +if test "$cross_compiling" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot compile a simple program; if not cross compiling check CC and CFLAGS" >&5 +$as_echo "cannot compile a simple program; if not cross compiling check CC and CFLAGS" >&6; } + CROSS_COMPILING=1 +fi + + +test "$GCC" = yes && CPP_MM=M; + +if test -f ./toolcheck; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for buggy tools" >&5 +$as_echo_n "checking for buggy tools... " >&6; } + sh ./toolcheck 1>&6 +fi + +OS_EXTRA_SRC=""; OS_EXTRA_OBJ="" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking uname" >&5 +$as_echo_n "checking uname... " >&6; } +if test "x$vim_cv_uname_output" = "x" ; then + vim_cv_uname_output=`(uname) 2>/dev/null` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_uname_output" >&5 +$as_echo "$vim_cv_uname_output" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_uname_output (cached)" >&5 +$as_echo "$vim_cv_uname_output (cached)" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking uname -r" >&5 +$as_echo_n "checking uname -r... " >&6; } +if test "x$vim_cv_uname_r_output" = "x" ; then + vim_cv_uname_r_output=`(uname -r) 2>/dev/null` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_uname_r_output" >&5 +$as_echo "$vim_cv_uname_r_output" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_uname_r_output (cached)" >&5 +$as_echo "$vim_cv_uname_r_output (cached)" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking uname -m" >&5 +$as_echo_n "checking uname -m... " >&6; } +if test "x$vim_cv_uname_m_output" = "x" ; then + vim_cv_uname_m_output=`(uname -m) 2>/dev/null` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_uname_m_output" >&5 +$as_echo "$vim_cv_uname_m_output" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_uname_m_output (cached)" >&5 +$as_echo "$vim_cv_uname_m_output (cached)" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Haiku" >&5 +$as_echo_n "checking for Haiku... " >&6; } +case $vim_cv_uname_output in + Haiku) HAIKU=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; };; + *) HAIKU=no; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; };; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for QNX" >&5 +$as_echo_n "checking for QNX... " >&6; } +case $vim_cv_uname_output in + QNX) OS_EXTRA_SRC=os_qnx.c; OS_EXTRA_OBJ=objects/os_qnx.o + test -z "$with_x" && with_x=no + QNX=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; };; + *) QNX=no; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; };; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Darwin (Mac OS X)" >&5 +$as_echo_n "checking for Darwin (Mac OS X)... " >&6; } +if test "$vim_cv_uname_output" = Darwin; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + MACOS_X=yes + CPPFLAGS="$CPPFLAGS -DMACOS_X" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-darwin argument" >&5 +$as_echo_n "checking --disable-darwin argument... " >&6; } + # Check whether --enable-darwin was given. +if test "${enable_darwin+set}" = set; then : + enableval=$enable_darwin; +else + enable_darwin="yes" +fi + + if test "$enable_darwin" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Darwin files are there" >&5 +$as_echo_n "checking if Darwin files are there... " >&6; } + if test -f os_macosx.m; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, Darwin support disabled" >&5 +$as_echo "no, Darwin support disabled" >&6; } + enable_darwin=no + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, Darwin support excluded" >&5 +$as_echo "yes, Darwin support excluded" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-mac-arch argument" >&5 +$as_echo_n "checking --with-mac-arch argument... " >&6; } + +# Check whether --with-mac-arch was given. +if test "${with_mac_arch+set}" = set; then : + withval=$with_mac_arch; MACARCH="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MACARCH" >&5 +$as_echo "$MACARCH" >&6; } +else + MACARCH="current"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to $MACARCH" >&5 +$as_echo "defaulting to $MACARCH" >&6; } +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-developer-dir argument" >&5 +$as_echo_n "checking --with-developer-dir argument... " >&6; } + +# Check whether --with-developer-dir was given. +if test "${with_developer_dir+set}" = set; then : + withval=$with_developer_dir; DEVELOPER_DIR="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEVELOPER_DIR" >&5 +$as_echo "$DEVELOPER_DIR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not present" >&5 +$as_echo "not present" >&6; } +fi + + + if test "x$DEVELOPER_DIR" = "x"; then + # Extract the first word of "xcode-select", so it can be a program name with args. +set dummy xcode-select; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_XCODE_SELECT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $XCODE_SELECT in + [\\/]* | ?:[\\/]*) + ac_cv_path_XCODE_SELECT="$XCODE_SELECT" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_XCODE_SELECT="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +XCODE_SELECT=$ac_cv_path_XCODE_SELECT +if test -n "$XCODE_SELECT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XCODE_SELECT" >&5 +$as_echo "$XCODE_SELECT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$XCODE_SELECT" != "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for developer dir using xcode-select" >&5 +$as_echo_n "checking for developer dir using xcode-select... " >&6; } + DEVELOPER_DIR=`$XCODE_SELECT -print-path` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEVELOPER_DIR" >&5 +$as_echo "$DEVELOPER_DIR" >&6; } + else + DEVELOPER_DIR=/Developer + fi + fi + + if test "x$MACARCH" = "xboth"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 10.4 universal SDK" >&5 +$as_echo_n "checking for 10.4 universal SDK... " >&6; } + save_cppflags="$CPPFLAGS" + save_cflags="$CFLAGS" + save_ldflags="$LDFLAGS" + CFLAGS="$CFLAGS -isysroot $DEVELOPER_DIR/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 +$as_echo "found" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + CFLAGS="$save_cflags" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Intel architecture is supported" >&5 +$as_echo_n "checking if Intel architecture is supported... " >&6; } + CPPFLAGS="$CPPFLAGS -arch i386" + LDFLAGS="$save_ldflags -arch i386" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; MACARCH="intel" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + MACARCH="ppc" + CPPFLAGS="$save_cppflags -arch ppc" + LDFLAGS="$save_ldflags -arch ppc" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + elif test "x$MACARCH" = "xintel"; then + CPPFLAGS="$CPPFLAGS -arch intel" + LDFLAGS="$LDFLAGS -arch intel" + elif test "x$MACARCH" = "xppc"; then + CPPFLAGS="$CPPFLAGS -arch ppc" + LDFLAGS="$LDFLAGS -arch ppc" + fi + + if test "$enable_darwin" = "yes"; then + MACOS_X_DARWIN=yes + OS_EXTRA_SRC="os_macosx.m os_mac_conv.c"; + OS_EXTRA_OBJ="objects/os_macosx.o objects/os_mac_conv.o" + $as_echo "#define HAVE_TIMER_CREATE 1" >>confdefs.h + + CPPFLAGS="$CPPFLAGS -DMACOS_X_DARWIN" + + if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xgtk2 -a "X$enable_gui" != Xgtk3; then + with_x=no + fi + fi + + if test "$MACARCH" = "intel" -o "$MACARCH" = "both"; then + CFLAGS=`echo "$CFLAGS" | sed 's/-O[23456789]/-Oz/'` + fi + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in AvailabilityMacros.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "AvailabilityMacros.h" "ac_cv_header_AvailabilityMacros_h" "$ac_includes_default" +if test "x$ac_cv_header_AvailabilityMacros_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_AVAILABILITYMACROS_H 1 +_ACEOF + +fi + +done + +# 10.5 and earlier lack dispatch +for ac_header in dispatch/dispatch.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "dispatch/dispatch.h" "ac_cv_header_dispatch_dispatch_h" "$ac_includes_default" +if test "x$ac_cv_header_dispatch_dispatch_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DISPATCH_DISPATCH_H 1 +_ACEOF + +fi + +done + + + + + +if test "$cross_compiling" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-local-dir argument" >&5 +$as_echo_n "checking --with-local-dir argument... " >&6; } + have_local_include='' + have_local_lib='' + +# Check whether --with-local-dir was given. +if test "${with_local_dir+set}" = set; then : + withval=$with_local_dir; + local_dir="$withval" + case "$withval" in + */*) ;; + no) + # avoid adding local dir to LDFLAGS and CPPFLAGS + have_local_include=yes + have_local_lib=yes + ;; + *) as_fn_error $? "must pass path argument to --with-local-dir" "$LINENO" 5 ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $local_dir" >&5 +$as_echo "$local_dir" >&6; } + +else + + local_dir=/usr/local + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to $local_dir" >&5 +$as_echo "Defaulting to $local_dir" >&6; } + +fi + + if test "$GCC" = yes -a "$local_dir" != no; then + echo 'void f(){}' > conftest.c + have_local_include=`${CC-cc} -c -v conftest.c 2>&1 | grep "${local_dir}/include"` + have_local_lib=`${CC-cc} -c -v conftest.c 2>&1 | grep "${local_dir}/lib"` + rm -f conftest.c conftest.o + fi + if test -z "$have_local_lib" -a -d "${local_dir}/lib"; then + tt=`echo "$LDFLAGS" | sed -e "s+-L${local_dir}/lib ++g" -e "s+-L${local_dir}/lib$++g"` + if test "$tt" = "$LDFLAGS"; then + LDFLAGS="$LDFLAGS -L${local_dir}/lib" + fi + fi + if test -z "$have_local_include" -a -d "${local_dir}/include"; then + tt=`echo "$CPPFLAGS" | sed -e "s+-I${local_dir}/include ++g" -e "s+-I${local_dir}/include$++g"` + if test "$tt" = "$CPPFLAGS"; then + CPPFLAGS="$CPPFLAGS -I${local_dir}/include" + fi + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-vim-name argument" >&5 +$as_echo_n "checking --with-vim-name argument... " >&6; } + +# Check whether --with-vim-name was given. +if test "${with_vim_name+set}" = set; then : + withval=$with_vim_name; VIMNAME="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $VIMNAME" >&5 +$as_echo "$VIMNAME" >&6; } +else + VIMNAME="vim"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to $VIMNAME" >&5 +$as_echo "Defaulting to $VIMNAME" >&6; } +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-ex-name argument" >&5 +$as_echo_n "checking --with-ex-name argument... " >&6; } + +# Check whether --with-ex-name was given. +if test "${with_ex_name+set}" = set; then : + withval=$with_ex_name; EXNAME="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $EXNAME" >&5 +$as_echo "$EXNAME" >&6; } +else + EXNAME="ex"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to ex" >&5 +$as_echo "Defaulting to ex" >&6; } +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-view-name argument" >&5 +$as_echo_n "checking --with-view-name argument... " >&6; } + +# Check whether --with-view-name was given. +if test "${with_view_name+set}" = set; then : + withval=$with_view_name; VIEWNAME="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $VIEWNAME" >&5 +$as_echo "$VIEWNAME" >&6; } +else + VIEWNAME="view"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to view" >&5 +$as_echo "Defaulting to view" >&6; } +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-global-runtime argument" >&5 +$as_echo_n "checking --with-global-runtime argument... " >&6; } + +# Check whether --with-global-runtime was given. +if test "${with_global_runtime+set}" = set; then : + withval=$with_global_runtime; RUNTIME_GLOBAL="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 +$as_echo "$withval" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +if test "X$RUNTIME_GLOBAL" != "X"; then + RUNTIME_GLOBAL_AFTER=$(printf -- "$RUNTIME_GLOBAL\\n" | $AWK -F, 'BEGIN { comma=0 } { for (i = NF; i > 0; i--) { if (comma) { printf ",%s/after", $i } else { printf "%s/after", $i; comma=1 } } } END { printf "\n" }') + cat >>confdefs.h <<_ACEOF +#define RUNTIME_GLOBAL "$RUNTIME_GLOBAL" +_ACEOF + + cat >>confdefs.h <<_ACEOF +#define RUNTIME_GLOBAL_AFTER "$RUNTIME_GLOBAL_AFTER" +_ACEOF + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-modified-by argument" >&5 +$as_echo_n "checking --with-modified-by argument... " >&6; } + +# Check whether --with-modified-by was given. +if test "${with_modified_by+set}" = set; then : + withval=$with_modified_by; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 +$as_echo "$withval" >&6; }; cat >>confdefs.h <<_ACEOF +#define MODIFIED_BY "$withval" +_ACEOF + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if character set is EBCDIC" >&5 +$as_echo_n "checking if character set is EBCDIC... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + /* TryCompile function for CharSet. + Treat any failure as ASCII for compatibility with existing art. + Use compile-time rather than run-time tests for cross-compiler + tolerance. */ +#if '0'!=240 +make an error "Character set is not EBCDIC" +#endif + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # TryCompile action if true +cf_cv_ebcdic=yes +else + # TryCompile action if false +cf_cv_ebcdic=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# end of TryCompile ]) +# end of CacheVal CvEbcdic +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cf_cv_ebcdic" >&5 +$as_echo "$cf_cv_ebcdic" >&6; } +case "$cf_cv_ebcdic" in #(vi + yes) $as_echo "#define EBCDIC 1" >>confdefs.h + + line_break='"\\n"' + ;; + *) line_break='"\\012"';; +esac + + +if test "$cf_cv_ebcdic" = "yes"; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for z/OS Unix" >&5 +$as_echo_n "checking for z/OS Unix... " >&6; } +case $vim_cv_uname_output in + OS/390) zOSUnix="yes"; + if test "$CC" = "cc"; then + ccm="$_CC_CCMODE" + ccn="CC" + else + if test "$CC" = "c89"; then + ccm="$_CC_C89MODE" + ccn="C89" + else + ccm=1 + fi + fi + if test "$ccm" != "1"; then + echo "" + echo "------------------------------------------" + echo " On z/OS Unix, the environment variable" + echo " _CC_${ccn}MODE must be set to \"1\"!" + echo " Do:" + echo " export _CC_${ccn}MODE=1" + echo " and then call configure again." + echo "------------------------------------------" + exit 1 + fi + # Set CFLAGS for configure process. + # This will be reset later for config.mk. + # Use haltonmsg to force error for missing H files. + CFLAGS="$CFLAGS -D_ALL_SOURCE -Wc,float(ieee),haltonmsg(3296)"; + LDFLAGS="$LDFLAGS -Wl,EDIT=NO" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ;; + *) zOSUnix="no"; + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; +esac +fi + +if test "$zOSUnix" = "yes"; then + QUOTESED="sed -e 's/[\\\\\"]/\\\\\\\\&/g' -e 's/\\\\\\\\\"/\"/' -e 's/\\\\\\\\\";\$\$/\";/' -e 's/ */ /g'" +else + QUOTESED="sed -e 's/[\\\\\"]/\\\\&/g' -e 's/\\\\\"/\"/' -e 's/\\\\\";\$\$/\";/' -e 's/ */ /g'" +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-smack argument" >&5 +$as_echo_n "checking --disable-smack argument... " >&6; } +# Check whether --enable-smack was given. +if test "${enable_smack+set}" = set; then : + enableval=$enable_smack; +else + enable_smack="yes" +fi + +if test "$enable_smack" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ac_fn_c_check_header_mongrel "$LINENO" "linux/xattr.h" "ac_cv_header_linux_xattr_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_xattr_h" = xyes; then : + true +else + enable_smack="no" +fi + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +if test "$enable_smack" = "yes"; then + ac_fn_c_check_header_mongrel "$LINENO" "attr/xattr.h" "ac_cv_header_attr_xattr_h" "$ac_includes_default" +if test "x$ac_cv_header_attr_xattr_h" = xyes; then : + true +else + enable_smack="no" +fi + + +fi +if test "$enable_smack" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XATTR_NAME_SMACKEXEC in linux/xattr.h" >&5 +$as_echo_n "checking for XATTR_NAME_SMACKEXEC in linux/xattr.h... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "XATTR_NAME_SMACKEXEC" >/dev/null 2>&1; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; enable_smack="no" +fi +rm -f conftest* + +fi +if test "$enable_smack" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setxattr in -lattr" >&5 +$as_echo_n "checking for setxattr in -lattr... " >&6; } +if ${ac_cv_lib_attr_setxattr+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lattr $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char setxattr (); +int +main () +{ +return setxattr (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_attr_setxattr=yes +else + ac_cv_lib_attr_setxattr=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_attr_setxattr" >&5 +$as_echo "$ac_cv_lib_attr_setxattr" >&6; } +if test "x$ac_cv_lib_attr_setxattr" = xyes; then : + LIBS="$LIBS -lattr" + found_smack="yes" + $as_echo "#define HAVE_SMACK 1" >>confdefs.h + +fi + +fi + +if test "x$found_smack" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-selinux argument" >&5 +$as_echo_n "checking --disable-selinux argument... " >&6; } + # Check whether --enable-selinux was given. +if test "${enable_selinux+set}" = set; then : + enableval=$enable_selinux; +else + enable_selinux="yes" +fi + + if test "$enable_selinux" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for is_selinux_enabled in -lselinux" >&5 +$as_echo_n "checking for is_selinux_enabled in -lselinux... " >&6; } +if ${ac_cv_lib_selinux_is_selinux_enabled+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lselinux $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char is_selinux_enabled (); +int +main () +{ +return is_selinux_enabled (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_selinux_is_selinux_enabled=yes +else + ac_cv_lib_selinux_is_selinux_enabled=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_selinux_is_selinux_enabled" >&5 +$as_echo "$ac_cv_lib_selinux_is_selinux_enabled" >&6; } +if test "x$ac_cv_lib_selinux_is_selinux_enabled" = xyes; then : + ac_fn_c_check_header_mongrel "$LINENO" "selinux/selinux.h" "ac_cv_header_selinux_selinux_h" "$ac_includes_default" +if test "x$ac_cv_header_selinux_selinux_h" = xyes; then : + LIBS="$LIBS -lselinux" + $as_echo "#define HAVE_SELINUX 1" >>confdefs.h + +fi + + +fi + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-features argument" >&5 +$as_echo_n "checking --with-features argument... " >&6; } + +# Check whether --with-features was given. +if test "${with_features+set}" = set; then : + withval=$with_features; features="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $features" >&5 +$as_echo "$features" >&6; } +else + features="huge"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to huge" >&5 +$as_echo "Defaulting to huge" >&6; } +fi + + +case "$features" in + small) features="tiny" ;; + big) features="normal" ;; +esac + +dovimdiff="" +dogvimdiff="" +case "$features" in + tiny) $as_echo "#define FEAT_TINY 1" >>confdefs.h + ;; + normal) $as_echo "#define FEAT_NORMAL 1" >>confdefs.h + dovimdiff="installvimdiff"; + dogvimdiff="installgvimdiff" ;; + huge) $as_echo "#define FEAT_HUGE 1" >>confdefs.h + dovimdiff="installvimdiff"; + dogvimdiff="installgvimdiff" ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Sorry, $features is not supported" >&5 +$as_echo "Sorry, $features is not supported" >&6; } ;; +esac + + + + +if test "x$features" = "xtiny"; then + has_eval=no +else + has_eval=yes +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-compiledby argument" >&5 +$as_echo_n "checking --with-compiledby argument... " >&6; } + +# Check whether --with-compiledby was given. +if test "${with_compiledby+set}" = set; then : + withval=$with_compiledby; compiledby="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 +$as_echo "$withval" >&6; } +else + compiledby=""; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-xsmp argument" >&5 +$as_echo_n "checking --disable-xsmp argument... " >&6; } +# Check whether --enable-xsmp was given. +if test "${enable_xsmp+set}" = set; then : + enableval=$enable_xsmp; +else + enable_xsmp="yes" +fi + + +if test "$enable_xsmp" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-xsmp-interact argument" >&5 +$as_echo_n "checking --disable-xsmp-interact argument... " >&6; } + # Check whether --enable-xsmp-interact was given. +if test "${enable_xsmp_interact+set}" = set; then : + enableval=$enable_xsmp_interact; +else + enable_xsmp_interact="yes" +fi + + if test "$enable_xsmp_interact" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + $as_echo "#define USE_XSMP_INTERACT 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking diff feature" >&5 +$as_echo_n "checking diff feature... " >&6; } +if test "x$features" = "xtiny"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled in $features version" >&5 +$as_echo "disabled in $features version" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 +$as_echo "enabled" >&6; } + $as_echo "#define FEAT_DIFF 1" >>confdefs.h + + XDIFF_OBJS_USED="\$(XDIFF_OBJS)" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-luainterp argument" >&5 +$as_echo_n "checking --enable-luainterp argument... " >&6; } +# Check whether --enable-luainterp was given. +if test "${enable_luainterp+set}" = set; then : + enableval=$enable_luainterp; +else + enable_luainterp="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_luainterp" >&5 +$as_echo "$enable_luainterp" >&6; } + +if test "$enable_luainterp" = "yes" -o "$enable_luainterp" = "dynamic"; then + if test "$has_eval" = "no"; then + as_fn_error $? "cannot use Lua with tiny features" "$LINENO" 5 + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-lua-prefix argument" >&5 +$as_echo_n "checking --with-lua-prefix argument... " >&6; } + +# Check whether --with-lua_prefix was given. +if test "${with_lua_prefix+set}" = set; then : + withval=$with_lua_prefix; with_lua_prefix="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_lua_prefix" >&5 +$as_echo "$with_lua_prefix" >&6; } +else + with_lua_prefix="";{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "X$with_lua_prefix" != "X"; then + vi_cv_path_lua_pfx="$with_lua_prefix" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking LUA_PREFIX environment var" >&5 +$as_echo_n "checking LUA_PREFIX environment var... " >&6; } + if test "X$LUA_PREFIX" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$LUA_PREFIX\"" >&5 +$as_echo "\"$LUA_PREFIX\"" >&6; } + vi_cv_path_lua_pfx="$LUA_PREFIX" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not set, default to /usr" >&5 +$as_echo "not set, default to /usr" >&6; } + vi_cv_path_lua_pfx="/usr" + fi + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-luajit" >&5 +$as_echo_n "checking --with-luajit... " >&6; } + +# Check whether --with-luajit was given. +if test "${with_luajit+set}" = set; then : + withval=$with_luajit; vi_cv_with_luajit="$withval" +else + vi_cv_with_luajit="no" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_with_luajit" >&5 +$as_echo "$vi_cv_with_luajit" >&6; } + + LUA_INC= + if test "X$vi_cv_path_lua_pfx" != "X"; then + if test "x$vi_cv_with_luajit" != "xno"; then + # Extract the first word of "luajit", so it can be a program name with args. +set dummy luajit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_luajit+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_luajit in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_luajit="$vi_cv_path_luajit" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_luajit="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_luajit=$ac_cv_path_vi_cv_path_luajit +if test -n "$vi_cv_path_luajit"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_luajit" >&5 +$as_echo "$vi_cv_path_luajit" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "X$vi_cv_path_luajit" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking LuaJIT version" >&5 +$as_echo_n "checking LuaJIT version... " >&6; } +if ${vi_cv_version_luajit+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_version_luajit=`${vi_cv_path_luajit} -v 2>&1 | sed 's/LuaJIT \([0-9.]*\)\.[0-9]\(-[a-z0-9]*\)* .*/\1/'` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_version_luajit" >&5 +$as_echo "$vi_cv_version_luajit" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Lua version of LuaJIT" >&5 +$as_echo_n "checking Lua version of LuaJIT... " >&6; } +if ${vi_cv_version_lua_luajit+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_version_lua_luajit=`${vi_cv_path_luajit} -e "print(_VERSION)" | sed 's/.* //'` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_version_lua_luajit" >&5 +$as_echo "$vi_cv_version_lua_luajit" >&6; } + vi_cv_path_lua="$vi_cv_path_luajit" + vi_cv_version_lua="$vi_cv_version_lua_luajit" + fi + else + # Extract the first word of "lua", so it can be a program name with args. +set dummy lua; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_plain_lua+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_plain_lua in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_plain_lua="$vi_cv_path_plain_lua" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_plain_lua="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_plain_lua=$ac_cv_path_vi_cv_path_plain_lua +if test -n "$vi_cv_path_plain_lua"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_plain_lua" >&5 +$as_echo "$vi_cv_path_plain_lua" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "X$vi_cv_path_plain_lua" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Lua version" >&5 +$as_echo_n "checking Lua version... " >&6; } +if ${vi_cv_version_plain_lua+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_version_plain_lua=`${vi_cv_path_plain_lua} -e "print(_VERSION)" | sed 's/.* //'` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_version_plain_lua" >&5 +$as_echo "$vi_cv_version_plain_lua" >&6; } + fi + vi_cv_path_lua="$vi_cv_path_plain_lua" + vi_cv_version_lua="$vi_cv_version_plain_lua" + fi + if test "x$vi_cv_with_luajit" != "xno" && test "X$vi_cv_version_luajit" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if lua.h can be found in $vi_cv_path_lua_pfx/include/luajit-$vi_cv_version_luajit" >&5 +$as_echo_n "checking if lua.h can be found in $vi_cv_path_lua_pfx/include/luajit-$vi_cv_version_luajit... " >&6; } + if test -f "$vi_cv_path_lua_pfx/include/luajit-$vi_cv_version_luajit/lua.h"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + LUA_INC=/luajit-$vi_cv_version_luajit + fi + fi + if test "X$LUA_INC" = "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if lua.h can be found in $vi_cv_path_lua_pfx/include" >&5 +$as_echo_n "checking if lua.h can be found in $vi_cv_path_lua_pfx/include... " >&6; } + if test -f "$vi_cv_path_lua_pfx/include/lua.h"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if lua.h can be found in $vi_cv_path_lua_pfx/include/lua$vi_cv_version_lua" >&5 +$as_echo_n "checking if lua.h can be found in $vi_cv_path_lua_pfx/include/lua$vi_cv_version_lua... " >&6; } + if test -f "$vi_cv_path_lua_pfx/include/lua$vi_cv_version_lua/lua.h"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + LUA_INC=/lua$vi_cv_version_lua + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + # Detect moonjit: + # https://groups.google.com/forum/#!topic/vim_use/O0vek60WuTk + lua_suf=/moonjit-2.3 + inc_path="$vi_cv_path_lua_pfx/include" + for dir in "$inc_path"/moonjit-[0-9]* ; do + if test -d "$dir" ; then + lua_suf=`basename "$dir"` + lua_suf="/$lua_suf" + break + fi + done + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if lua.h can be found in $inc_path$lua_suf" >&5 +$as_echo_n "checking if lua.h can be found in $inc_path$lua_suf... " >&6; } + if test -f "$inc_path$lua_suf/lua.h"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + LUA_INC=$lua_suf + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + vi_cv_path_lua_pfx= + fi + fi + fi + fi + fi + + if test "X$vi_cv_path_lua_pfx" != "X"; then + if test "x$vi_cv_with_luajit" != "xno"; then + multiarch=`dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null` + if test "X$multiarch" != "X"; then + lib_multiarch="lib/${multiarch}" + else + lib_multiarch="lib" + fi + if test "X$vi_cv_version_lua" = "X"; then + LUA_LIBS="-L${vi_cv_path_lua_pfx}/${lib_multiarch} -lluajit" + else + LUA_LIBS="-L${vi_cv_path_lua_pfx}/${lib_multiarch} -lluajit-$vi_cv_version_lua" + fi + else + if test "X$LUA_INC" != "X"; then + LUA_LIBS="-L${vi_cv_path_lua_pfx}/lib -llua$vi_cv_version_lua" + else + LUA_LIBS="-L${vi_cv_path_lua_pfx}/lib -llua" + fi + fi + if test "$enable_luainterp" = "dynamic"; then + lua_ok="yes" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if link with ${LUA_LIBS} is sane" >&5 +$as_echo_n "checking if link with ${LUA_LIBS} is sane... " >&6; } + libs_save=$LIBS + LIBS="$LIBS $LUA_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; lua_ok="yes" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; lua_ok="no"; LUA_LIBS="" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS=$libs_save + fi + if test "x$lua_ok" = "xyes"; then + LUA_CFLAGS="-I${vi_cv_path_lua_pfx}/include${LUA_INC}" + LUA_SRC="if_lua.c" + LUA_OBJ="objects/if_lua.o" + LUA_PRO="if_lua.pro" + $as_echo "#define FEAT_LUA 1" >>confdefs.h + + fi + if test "$enable_luainterp" = "dynamic"; then + if test "x$vi_cv_with_luajit" != "xno"; then + luajit="jit" + fi + if test -f "${vi_cv_path_lua_pfx}/bin/cyglua-${vi_cv_version_lua}.dll"; then + vi_cv_dll_name_lua="cyglua-${vi_cv_version_lua}.dll" + else + if test "x$MACOS_X" = "xyes"; then + ext="dylib" + indexes="" + else + ext="so" + indexes=".0 .1 .2 .3 .4 .5 .6 .7 .8 .9" + multiarch=`dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null` + if test "X$multiarch" != "X"; then + lib_multiarch="lib/${multiarch}" + fi + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if liblua${luajit}*.${ext}* can be found in $vi_cv_path_lua_pfx" >&5 +$as_echo_n "checking if liblua${luajit}*.${ext}* can be found in $vi_cv_path_lua_pfx... " >&6; } + for subdir in "${lib_multiarch}" lib64 lib; do + if test -z "$subdir"; then + continue + fi + for sover in "${vi_cv_version_lua}.${ext}" "-${vi_cv_version_lua}.${ext}" \ + ".${vi_cv_version_lua}.${ext}" ".${ext}.${vi_cv_version_lua}"; do + for i in $indexes ""; do + if test -f "${vi_cv_path_lua_pfx}/${subdir}/liblua${luajit}${sover}$i"; then + sover2="$i" + break 3 + fi + done + done + sover="" + done + if test "X$sover" = "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + lua_ok="no" + vi_cv_dll_name_lua="liblua${luajit}.${ext}" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + lua_ok="yes" + vi_cv_dll_name_lua="liblua${luajit}${sover}$sover2" + fi + fi + $as_echo "#define DYNAMIC_LUA 1" >>confdefs.h + + LUA_LIBS="" + LUA_CFLAGS="-DDYNAMIC_LUA_DLL=\\\"${vi_cv_dll_name_lua}\\\" $LUA_CFLAGS" + fi + if test "X$LUA_CFLAGS$LUA_LIBS" != "X" && \ + test "x$MACOS_X" = "xyes" && test "x$vi_cv_with_luajit" != "xno" && \ + test "$vim_cv_uname_m_output" = "x86_64"; then + LUA_LIBS="-pagezero_size 10000 -image_base 100000000 $LUA_LIBS" + fi + fi + if test "$fail_if_missing" = "yes" -a "$lua_ok" != "yes"; then + as_fn_error $? "could not configure lua" "$LINENO" 5 + fi + + + + + + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-mzschemeinterp argument" >&5 +$as_echo_n "checking --enable-mzschemeinterp argument... " >&6; } +# Check whether --enable-mzschemeinterp was given. +if test "${enable_mzschemeinterp+set}" = set; then : + enableval=$enable_mzschemeinterp; +else + enable_mzschemeinterp="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_mzschemeinterp" >&5 +$as_echo "$enable_mzschemeinterp" >&6; } + +if test "$enable_mzschemeinterp" = "yes"; then + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-plthome argument" >&5 +$as_echo_n "checking --with-plthome argument... " >&6; } + +# Check whether --with-plthome was given. +if test "${with_plthome+set}" = set; then : + withval=$with_plthome; with_plthome="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_plthome" >&5 +$as_echo "$with_plthome" >&6; } +else + with_plthome="";{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"no\"" >&5 +$as_echo "\"no\"" >&6; } +fi + + + if test "X$with_plthome" != "X"; then + vi_cv_path_mzscheme_pfx="$with_plthome" + vi_cv_path_mzscheme="${vi_cv_path_mzscheme_pfx}/bin/mzscheme" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking PLTHOME environment var" >&5 +$as_echo_n "checking PLTHOME environment var... " >&6; } + if test "X$PLTHOME" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$PLTHOME\"" >&5 +$as_echo "\"$PLTHOME\"" >&6; } + vi_cv_path_mzscheme_pfx="$PLTHOME" + vi_cv_path_mzscheme="${vi_cv_path_mzscheme_pfx}/bin/mzscheme" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not set" >&5 +$as_echo "not set" >&6; } + # Extract the first word of "mzscheme", so it can be a program name with args. +set dummy mzscheme; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_mzscheme+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_mzscheme in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_mzscheme="$vi_cv_path_mzscheme" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_mzscheme="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_mzscheme=$ac_cv_path_vi_cv_path_mzscheme +if test -n "$vi_cv_path_mzscheme"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_mzscheme" >&5 +$as_echo "$vi_cv_path_mzscheme" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + if test "X$vi_cv_path_mzscheme" != "X"; then + lsout=`ls -l $vi_cv_path_mzscheme` + if echo "$lsout" | grep -e '->' >/dev/null 2>/dev/null; then + vi_cv_path_mzscheme=`echo "$lsout" | sed 's/.*-> \(.*\)/\1/'` + fi + fi + + if test "X$vi_cv_path_mzscheme" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking MzScheme install prefix" >&5 +$as_echo_n "checking MzScheme install prefix... " >&6; } +if ${vi_cv_path_mzscheme_pfx+:} false; then : + $as_echo_n "(cached) " >&6 +else + echo "(display (simplify-path \ + (build-path (call-with-values \ + (lambda () (split-path (find-system-path (quote exec-file)))) \ + (lambda (base name must-be-dir?) base)) (quote up))))" > mzdirs.scm + vi_cv_path_mzscheme_pfx=`${vi_cv_path_mzscheme} -r mzdirs.scm | \ + sed -e 's+/$++'` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_mzscheme_pfx" >&5 +$as_echo "$vi_cv_path_mzscheme_pfx" >&6; } + rm -f mzdirs.scm + fi + fi + fi + + if test "X$vi_cv_path_mzscheme_pfx" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for racket include directory" >&5 +$as_echo_n "checking for racket include directory... " >&6; } + SCHEME_INC=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-include-dir))) (when (path? p) (display p)))'` + if test "X$SCHEME_INC" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${SCHEME_INC}" >&5 +$as_echo "${SCHEME_INC}" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include" >&5 +$as_echo_n "checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include... " >&6; } + if test -f "$vi_cv_path_mzscheme_pfx/include/scheme.h"; then + SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/plt" >&5 +$as_echo_n "checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/plt... " >&6; } + if test -f "$vi_cv_path_mzscheme_pfx/include/plt/scheme.h"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include/plt + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/racket" >&5 +$as_echo_n "checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/racket... " >&6; } + if test -f "$vi_cv_path_mzscheme_pfx/include/racket/scheme.h"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include/racket + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if scheme.h can be found in /usr/include/plt/" >&5 +$as_echo_n "checking if scheme.h can be found in /usr/include/plt/... " >&6; } + if test -f /usr/include/plt/scheme.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SCHEME_INC=/usr/include/plt + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if scheme.h can be found in /usr/include/racket/" >&5 +$as_echo_n "checking if scheme.h can be found in /usr/include/racket/... " >&6; } + if test -f /usr/include/racket/scheme.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SCHEME_INC=/usr/include/racket + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + vi_cv_path_mzscheme_pfx= + fi + fi + fi + fi + fi + fi + fi + + if test "X$vi_cv_path_mzscheme_pfx" != "X"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for racket lib directory" >&5 +$as_echo_n "checking for racket lib directory... " >&6; } + SCHEME_LIB=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-lib-dir))) (when (path? p) (display p)))'` + if test "X$SCHEME_LIB" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${SCHEME_LIB}" >&5 +$as_echo "${SCHEME_LIB}" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + fi + + for path in "${vi_cv_path_mzscheme_pfx}/lib" "${SCHEME_LIB}"; do + if test "X$path" != "X"; then + if test "x$MACOS_X" = "xyes"; then + MZSCHEME_LIBS="-framework Racket" + MZSCHEME_CFLAGS="-DMZ_PRECISE_GC" + elif test -f "${path}/libmzscheme3m.a"; then + MZSCHEME_LIBS="${path}/libmzscheme3m.a" + MZSCHEME_CFLAGS="-DMZ_PRECISE_GC" + elif test -f "${path}/libracket3m.a"; then + MZSCHEME_LIBS="${path}/libracket3m.a" + if test -f "${path}/librktio.a"; then + MZSCHEME_LIBS="${MZSCHEME_LIBS} ${path}/librktio.a" + fi + MZSCHEME_CFLAGS="-DMZ_PRECISE_GC" + elif test -f "${path}/libracket.a"; then + MZSCHEME_LIBS="${path}/libracket.a ${path}/libmzgc.a" + elif test -f "${path}/libmzscheme.a"; then + MZSCHEME_LIBS="${path}/libmzscheme.a ${path}/libmzgc.a" + else + if test -f "${path}/libmzscheme3m.so"; then + MZSCHEME_LIBS="-L${path} -lmzscheme3m" + MZSCHEME_CFLAGS="-DMZ_PRECISE_GC" + elif test -f "${path}/libracket3m.so"; then + MZSCHEME_LIBS="-L${path} -lracket3m" + MZSCHEME_CFLAGS="-DMZ_PRECISE_GC" + elif test -f "${path}/libracket.so"; then + MZSCHEME_LIBS="-L${path} -lracket -lmzgc" + else + if test "$path" != "$SCHEME_LIB"; then + continue + fi + MZSCHEME_LIBS="-L${path} -lmzscheme -lmzgc" + fi + if test "$GCC" = yes; then + MZSCHEME_LIBS="${MZSCHEME_LIBS} -Wl,-rpath -Wl,${path}" + elif test "$vim_cv_uname_output" = SunOS && + echo $vim_cv_uname_r_output | grep '^5' >/dev/null; then + MZSCHEME_LIBS="${MZSCHEME_LIBS} -R ${path}" + fi + fi + fi + if test "X$MZSCHEME_LIBS" != "X"; then + break + fi + done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if racket requires -pthread" >&5 +$as_echo_n "checking if racket requires -pthread... " >&6; } + if test "X$SCHEME_LIB" != "X" && $FGREP -e -pthread "$SCHEME_LIB/buildinfo" >/dev/null ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + MZSCHEME_LIBS="${MZSCHEME_LIBS} -pthread" + MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -pthread" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for racket config directory" >&5 +$as_echo_n "checking for racket config directory... " >&6; } + SCHEME_CONFIGDIR=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-config-dir))) (when (path? p) (display p)))'` + if test "X$SCHEME_CONFIGDIR" != "X"; then + MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -DMZSCHEME_CONFIGDIR='\"${SCHEME_CONFIGDIR}\"'" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${SCHEME_CONFIGDIR}" >&5 +$as_echo "${SCHEME_CONFIGDIR}" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for racket collects directory" >&5 +$as_echo_n "checking for racket collects directory... " >&6; } + SCHEME_COLLECTS=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-collects-dir))) (when (path? p) (let-values (((base _1 _2) (split-path p))) (display base))))'` + if test "X$SCHEME_COLLECTS" = "X"; then + if test -d "$vi_cv_path_mzscheme_pfx/lib/plt/collects"; then + SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/lib/plt/ + else + if test -d "$vi_cv_path_mzscheme_pfx/lib/racket/collects"; then + SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/lib/racket/ + else + if test -d "$vi_cv_path_mzscheme_pfx/share/racket/collects"; then + SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/share/racket/ + else + if test -d "$vi_cv_path_mzscheme_pfx/collects"; then + SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/ + fi + fi + fi + fi + fi + if test "X$SCHEME_COLLECTS" != "X" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${SCHEME_COLLECTS}" >&5 +$as_echo "${SCHEME_COLLECTS}" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mzscheme_base.c" >&5 +$as_echo_n "checking for mzscheme_base.c... " >&6; } + if test -f "${SCHEME_COLLECTS}collects/scheme/base.ss" ; then + MZSCHEME_EXTRA="mzscheme_base.c" + MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/mzc" + MZSCHEME_MOD="++lib scheme/base" + else + if test -f "${SCHEME_COLLECTS}collects/scheme/base.rkt" ; then + MZSCHEME_EXTRA="mzscheme_base.c" + MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/mzc" + MZSCHEME_MOD="++lib scheme/base" + else + if test -f "${SCHEME_COLLECTS}collects/racket/base.rkt" ; then + MZSCHEME_EXTRA="mzscheme_base.c" + MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/raco ctool" + MZSCHEME_MOD="" + fi + fi + fi + if test "X$MZSCHEME_EXTRA" != "X" ; then + MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -DINCLUDE_MZSCHEME_BASE" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: needed" >&5 +$as_echo "needed" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not needed" >&5 +$as_echo "not needed" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffi_type_void in -lffi" >&5 +$as_echo_n "checking for ffi_type_void in -lffi... " >&6; } +if ${ac_cv_lib_ffi_ffi_type_void+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lffi $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ffi_type_void (); +int +main () +{ +return ffi_type_void (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ffi_ffi_type_void=yes +else + ac_cv_lib_ffi_ffi_type_void=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_type_void" >&5 +$as_echo "$ac_cv_lib_ffi_ffi_type_void" >&6; } +if test "x$ac_cv_lib_ffi_ffi_type_void" = xyes; then : + MZSCHEME_LIBS="$MZSCHEME_LIBS -lffi" +fi + + + MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -I${SCHEME_INC} \ + -DMZSCHEME_COLLECTS='\"${SCHEME_COLLECTS}collects\"'" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compile and link flags for MzScheme are sane" >&5 +$as_echo_n "checking if compile and link flags for MzScheme are sane... " >&6; } + cflags_save=$CFLAGS + libs_save=$LIBS + CFLAGS="$CFLAGS $MZSCHEME_CFLAGS" + LIBS="$LIBS $MZSCHEME_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; mzs_ok=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no: MZSCHEME DISABLED" >&5 +$as_echo "no: MZSCHEME DISABLED" >&6; }; mzs_ok=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$cflags_save + LIBS=$libs_save + if test $mzs_ok = yes; then + MZSCHEME_SRC="if_mzsch.c" + MZSCHEME_OBJ="objects/if_mzsch.o" + MZSCHEME_PRO="if_mzsch.pro" + $as_echo "#define FEAT_MZSCHEME 1" >>confdefs.h + + else + MZSCHEME_CFLAGS= + MZSCHEME_LIBS= + MZSCHEME_EXTRA= + MZSCHEME_MZC= + fi + fi + + + + + + + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-perlinterp argument" >&5 +$as_echo_n "checking --enable-perlinterp argument... " >&6; } +# Check whether --enable-perlinterp was given. +if test "${enable_perlinterp+set}" = set; then : + enableval=$enable_perlinterp; +else + enable_perlinterp="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_perlinterp" >&5 +$as_echo "$enable_perlinterp" >&6; } +if test "$enable_perlinterp" = "yes" -o "$enable_perlinterp" = "dynamic"; then + if test "$has_eval" = "no"; then + as_fn_error $? "cannot use Perl with tiny features" "$LINENO" 5 + fi + + # Extract the first word of "perl", so it can be a program name with args. +set dummy perl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_perl+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_perl in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_perl="$vi_cv_path_perl" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_perl="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_perl=$ac_cv_path_vi_cv_path_perl +if test -n "$vi_cv_path_perl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_perl" >&5 +$as_echo "$vi_cv_path_perl" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "X$vi_cv_path_perl" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Perl version" >&5 +$as_echo_n "checking Perl version... " >&6; } + if $vi_cv_path_perl -e 'require 5.003_01' >/dev/null 2>/dev/null; then + eval `$vi_cv_path_perl -V:usethreads` + eval `$vi_cv_path_perl -V:libperl` + if test "X$usethreads" = "XUNKNOWN" -o "X$usethreads" = "Xundef"; then + badthreads=no + else + if $vi_cv_path_perl -e 'require 5.6.0' >/dev/null 2>/dev/null; then + eval `$vi_cv_path_perl -V:use5005threads` + if test "X$use5005threads" = "XUNKNOWN" -o "X$use5005threads" = "Xundef"; then + badthreads=no + else + badthreads=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: >>> Perl > 5.6 with 5.5 threads cannot be used <<<" >&5 +$as_echo ">>> Perl > 5.6 with 5.5 threads cannot be used <<<" >&6; } + fi + else + badthreads=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: >>> Perl 5.5 with threads cannot be used <<<" >&5 +$as_echo ">>> Perl 5.5 with threads cannot be used <<<" >&6; } + fi + fi + if test $badthreads = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK" >&5 +$as_echo "OK" >&6; } + eval `$vi_cv_path_perl -V:shrpenv` + if test "X$shrpenv" = "XUNKNOWN"; then # pre 5.003_04 + shrpenv="" + fi + vi_cv_perllib=`$vi_cv_path_perl -MConfig -e 'print $Config{privlibexp}'` + + vi_cv_perl_extutils=unknown_perl_extutils_path + for extutils_rel_path in ExtUtils vendor_perl/ExtUtils; do + xsubpp_path="$vi_cv_perllib/$extutils_rel_path/xsubpp" + if test -f "$xsubpp_path"; then + vi_cv_perl_xsubpp="$xsubpp_path" + fi + done + + perlcppflags=`$vi_cv_path_perl -Mlib=$srcdir -MExtUtils::Embed \ + -e 'ccflags;perl_inc;print"\n"' | sed -e 's/-fno[^ ]*//' \ + -e 's/-fdebug-prefix-map[^ ]*//g' \ + -e 's/-pipe //' \ + -e 's/-W[^ ]*//g' \ + -e 's/-D_FORTIFY_SOURCE=.//g'` + perllibs=`cd $srcdir; $vi_cv_path_perl -MExtUtils::Embed -e 'ldopts' | \ + sed -e '/Warning/d' -e '/Note (probably harmless)/d' \ + -e 's/-bE:perl.exp//' -e 's/-lc //'` + perlldflags=`cd $srcdir; $vi_cv_path_perl -MExtUtils::Embed \ + -e 'ccdlflags' | sed -e 's/-bE:perl.exp//'` + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compile and link flags for Perl are sane" >&5 +$as_echo_n "checking if compile and link flags for Perl are sane... " >&6; } + cflags_save=$CFLAGS + libs_save=$LIBS + ldflags_save=$LDFLAGS + CFLAGS="$CFLAGS $perlcppflags" + LIBS="$LIBS $perllibs" + perlldflags=`echo "$perlldflags" | sed -e 's/^ *//g'` + LDFLAGS="$perlldflags $LDFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; perl_ok=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no: PERL DISABLED" >&5 +$as_echo "no: PERL DISABLED" >&6; }; perl_ok=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$cflags_save + LIBS=$libs_save + LDFLAGS=$ldflags_save + if test $perl_ok = yes; then + if test "X$perlcppflags" != "X"; then + PERL_CFLAGS=$perlcppflags + fi + if test "X$perlldflags" != "X"; then + if test "X`echo \"$LDFLAGS\" | $FGREP -e \"$perlldflags\"`" = "X"; then + LDFLAGS="$perlldflags $LDFLAGS" + fi + fi + PERL_LIBS=$perllibs + PERL_SRC="auto/if_perl.c if_perlsfio.c" + PERL_OBJ="objects/if_perl.o objects/if_perlsfio.o" + PERL_PRO="if_perl.pro if_perlsfio.pro" + $as_echo "#define FEAT_PERL 1" >>confdefs.h + + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: >>> too old; need Perl version 5.003_01 or later <<<" >&5 +$as_echo ">>> too old; need Perl version 5.003_01 or later <<<" >&6; } + fi + fi + + if test "x$MACOS_X" = "xyes"; then + dir=/System/Library/Perl + darwindir=$dir/darwin + if test -d $darwindir; then + PERL=/usr/bin/perl + else + dir=/System/Library/Perl/5.8.1 + darwindir=$dir/darwin-thread-multi-2level + if test -d $darwindir; then + PERL=/usr/bin/perl + fi + fi + if test -n "$PERL"; then + PERL_DIR="$dir" + PERL_CFLAGS="-DFEAT_PERL -I$darwindir/CORE" + PERL_OBJ="objects/if_perl.o objects/if_perlsfio.o $darwindir/auto/DynaLoader/DynaLoader.a" + PERL_LIBS="-L$darwindir/CORE -lperl" + fi + PERL_LIBS=`echo "$PERL_LIBS" | sed -e 's/-arch\ ppc//' -e 's/-arch\ i386//' -e 's/-arch\ x86_64//'` + PERL_CFLAGS=`echo "$PERL_CFLAGS" | sed -e 's/-arch\ ppc//' -e 's/-arch\ i386//' -e 's/-arch\ x86_64//'` + fi + if test "$enable_perlinterp" = "dynamic"; then + if test "$perl_ok" = "yes" -a "X$libperl" != "X"; then + $as_echo "#define DYNAMIC_PERL 1" >>confdefs.h + + PERL_CFLAGS="-DDYNAMIC_PERL_DLL=\\\"$libperl\\\" $PERL_CFLAGS" + fi + fi + + if test "$fail_if_missing" = "yes" -a "$perl_ok" != "yes"; then + as_fn_error $? "could not configure perl" "$LINENO" 5 + fi +fi + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-pythoninterp argument" >&5 +$as_echo_n "checking --enable-pythoninterp argument... " >&6; } +# Check whether --enable-pythoninterp was given. +if test "${enable_pythoninterp+set}" = set; then : + enableval=$enable_pythoninterp; +else + enable_pythoninterp="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_pythoninterp" >&5 +$as_echo "$enable_pythoninterp" >&6; } +if test "$enable_pythoninterp" = "yes" -o "$enable_pythoninterp" = "dynamic"; then + if test "$has_eval" = "no"; then + as_fn_error $? "cannot use Python with tiny features" "$LINENO" 5 + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-python-command argument" >&5 +$as_echo_n "checking --with-python-command argument... " >&6; } + + +# Check whether --with-python-command was given. +if test "${with_python_command+set}" = set; then : + withval=$with_python_command; vi_cv_path_python="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python" >&5 +$as_echo "$vi_cv_path_python" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "X$vi_cv_path_python" = "X"; then + for ac_prog in python2 python +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_python+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_python in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_python="$vi_cv_path_python" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_python="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_python=$ac_cv_path_vi_cv_path_python +if test -n "$vi_cv_path_python"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python" >&5 +$as_echo "$vi_cv_path_python" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$vi_cv_path_python" && break +done + + fi + if test "X$vi_cv_path_python" != "X"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python version" >&5 +$as_echo_n "checking Python version... " >&6; } +if ${vi_cv_var_python_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_var_python_version=` + ${vi_cv_path_python} -c 'import sys; print sys.version[:3]'` + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_var_python_version" >&5 +$as_echo "$vi_cv_var_python_version" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python is 2.3 or better" >&5 +$as_echo_n "checking Python is 2.3 or better... " >&6; } + if ${vi_cv_path_python} -c \ + "import sys; sys.exit(${vi_cv_var_python_version} < 2.3)" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yep" >&5 +$as_echo "yep" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's install prefix" >&5 +$as_echo_n "checking Python's install prefix... " >&6; } +if ${vi_cv_path_python_pfx+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_path_python_pfx=` + ${vi_cv_path_python} -c \ + "import sys; print sys.prefix"` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python_pfx" >&5 +$as_echo "$vi_cv_path_python_pfx" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's execution prefix" >&5 +$as_echo_n "checking Python's execution prefix... " >&6; } +if ${vi_cv_path_python_epfx+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_path_python_epfx=` + ${vi_cv_path_python} -c \ + "import sys; print sys.exec_prefix"` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python_epfx" >&5 +$as_echo "$vi_cv_path_python_epfx" >&6; } + + + if ${vi_cv_path_pythonpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_path_pythonpath=` + unset PYTHONPATH; + ${vi_cv_path_python} -c \ + "import sys, string; print string.join(sys.path,':')"` +fi + + + + +# Check whether --with-python-config-dir was given. +if test "${with_python_config_dir+set}" = set; then : + withval=$with_python_config_dir; vi_cv_path_python_conf="${withval}"; have_python_config_dir=1 +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's configuration directory" >&5 +$as_echo_n "checking Python's configuration directory... " >&6; } +if ${vi_cv_path_python_conf+:} false; then : + $as_echo_n "(cached) " >&6 +else + + vi_cv_path_python_conf= + d=`${vi_cv_path_python} -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('LIBPL')"` + if test -d "$d" && test -f "$d/config.c"; then + vi_cv_path_python_conf="$d" + else + for path in "${vi_cv_path_python_pfx}" "${vi_cv_path_python_epfx}"; do + for subdir in lib64 lib share; do + d="${path}/${subdir}/python${vi_cv_var_python_version}/config" + if test -d "$d" && test -f "$d/config.c"; then + vi_cv_path_python_conf="$d" + fi + done + done + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python_conf" >&5 +$as_echo "$vi_cv_path_python_conf" >&6; } + + PYTHON_CONFDIR="${vi_cv_path_python_conf}" + + if test "X$PYTHON_CONFDIR" = "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: can't find it!" >&5 +$as_echo "can't find it!" >&6; } + else + + if ${vi_cv_path_python_plibs+:} false; then : + $as_echo_n "(cached) " >&6 +else + + pwd=`pwd` + tmp_mkf="$pwd/config-PyMake$$" + cat -- "${PYTHON_CONFDIR}/Makefile" - <<'eof' >"${tmp_mkf}" +__: + @echo "python_BASEMODLIBS='$(BASEMODLIBS)'" + @echo "python_LIBS='$(LIBS)'" + @echo "python_SYSLIBS='$(SYSLIBS)'" + @echo "python_LINKFORSHARED='$(LINKFORSHARED)'" + @echo "python_DLLLIBRARY='$(DLLLIBRARY)'" + @echo "python_INSTSONAME='$(INSTSONAME)'" + @echo "python_PYTHONFRAMEWORK='$(PYTHONFRAMEWORK)'" + @echo "python_PYTHONFRAMEWORKPREFIX='$(PYTHONFRAMEWORKPREFIX)'" + @echo "python_PYTHONFRAMEWORKINSTALLDIR='$(PYTHONFRAMEWORKINSTALLDIR)'" +eof + eval "`cd ${PYTHON_CONFDIR} && make -f "${tmp_mkf}" __ | sed '/ directory /d'`" + rm -f -- "${tmp_mkf}" + if test "x$MACOS_X" = "xyes" && test -n "${python_PYTHONFRAMEWORK}" && ${vi_cv_path_python} -c \ + "import sys; sys.exit(${vi_cv_var_python_version} < 2.3)"; then + vi_cv_path_python_plibs="-framework Python" + if test "x${vi_cv_path_python}" != "x/usr/bin/python" && test -n "${python_PYTHONFRAMEWORKPREFIX}"; then + vi_cv_path_python_plibs="-F${python_PYTHONFRAMEWORKPREFIX} -framework Python" + fi + else + vi_cv_path_python_plibs="-L${PYTHON_CONFDIR} -lpython${vi_cv_var_python_version}" + if test -n "${python_LINKFORSHARED}" && test -n "${python_PYTHONFRAMEWORKPREFIX}"; then + python_link_symbol=`echo ${python_LINKFORSHARED} | sed 's/\([^ \t][^ \t]*[ \t][ \t]*[^ \t][^ \t]*\)[ \t].*/\1/'` + python_link_path=`echo ${python_LINKFORSHARED} | sed 's/\([^ \t][^ \t]*[ \t][ \t]*[^ \t][^ \t]*\)[ \t][ \t]*\(.*\)/\2/'` + if test -n "${python_link_path}" && ! test -x "${python_link_path}"; then + python_link_path="${python_PYTHONFRAMEWORKPREFIX}/${python_link_path}" + if test -n "${python_link_path}" && ! test -x "${python_link_path}"; then + python_link_path="${python_PYTHONFRAMEWORKINSTALLDIR}/Versions/${vi_cv_var_python_version}/${python_PYTHONFRAMEWORK}" + fi + python_LINKFORSHARED="${python_link_symbol} ${python_link_path}" + fi + fi + vi_cv_path_python_plibs="${vi_cv_path_python_plibs} ${python_BASEMODLIBS} ${python_LIBS} ${python_SYSLIBS} ${python_LINKFORSHARED}" + vi_cv_path_python_plibs=`echo $vi_cv_path_python_plibs | sed s/-ltermcap//` + fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's dll name" >&5 +$as_echo_n "checking Python's dll name... " >&6; } +if ${vi_cv_dll_name_python+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "X$python_DLLLIBRARY" != "X"; then + vi_cv_dll_name_python="$python_DLLLIBRARY" + else + vi_cv_dll_name_python="$python_INSTSONAME" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_dll_name_python" >&5 +$as_echo "$vi_cv_dll_name_python" >&6; } + + PYTHON_LIBS="${vi_cv_path_python_plibs}" + if test "${vi_cv_path_python_pfx}" = "${vi_cv_path_python_epfx}"; then + PYTHON_CFLAGS="-I${vi_cv_path_python_pfx}/include/python${vi_cv_var_python_version}" + else + PYTHON_CFLAGS="-I${vi_cv_path_python_pfx}/include/python${vi_cv_var_python_version} -I${vi_cv_path_python_epfx}/include/python${vi_cv_var_python_version}" + fi + if test "X$have_python_config_dir" = "X1" -a "$enable_pythoninterp" = "dynamic"; then + PYTHON_CFLAGS="${PYTHON_CFLAGS} -DPYTHON_HOME='\"${vi_cv_path_python_pfx}\"'" + + fi + PYTHON_SRC="if_python.c" + PYTHON_OBJ="objects/if_python.o" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -pthread should be used" >&5 +$as_echo_n "checking if -pthread should be used... " >&6; } + threadsafe_flag= + thread_lib= + if test "$vim_cv_uname_output" != Darwin; then + test "$GCC" = yes && threadsafe_flag="-pthread" + if test "$vim_cv_uname_output" = FreeBSD; then + threadsafe_flag="-D_THREAD_SAFE" + thread_lib="-pthread" + fi + if test "$vim_cv_uname_output" = SunOS; then + threadsafe_flag="-pthreads" + fi + fi + libs_save_old=$LIBS + if test -n "$threadsafe_flag"; then + cflags_save=$CFLAGS + CFLAGS="$CFLAGS $threadsafe_flag" + LIBS="$LIBS $thread_lib" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; PYTHON_CFLAGS="$PYTHON_CFLAGS $threadsafe_flag" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; LIBS=$libs_save_old + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$cflags_save + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compile and link flags for Python are sane" >&5 +$as_echo_n "checking if compile and link flags for Python are sane... " >&6; } + cflags_save=$CFLAGS + libs_save=$LIBS + CFLAGS="$CFLAGS $PYTHON_CFLAGS" + LIBS="$LIBS $PYTHON_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; python_ok=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no: PYTHON DISABLED" >&5 +$as_echo "no: PYTHON DISABLED" >&6; }; python_ok=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$cflags_save + LIBS=$libs_save + if test $python_ok = yes; then + $as_echo "#define FEAT_PYTHON 1" >>confdefs.h + + else + LIBS=$libs_save_old + PYTHON_SRC= + PYTHON_OBJ= + PYTHON_LIBS= + PYTHON_CFLAGS= + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: too old" >&5 +$as_echo "too old" >&6; } + fi + fi + + if test "$fail_if_missing" = "yes" -a "$python_ok" != "yes"; then + as_fn_error $? "could not configure python" "$LINENO" 5 + fi +fi + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-python3interp argument" >&5 +$as_echo_n "checking --enable-python3interp argument... " >&6; } +# Check whether --enable-python3interp was given. +if test "${enable_python3interp+set}" = set; then : + enableval=$enable_python3interp; +else + enable_python3interp="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_python3interp" >&5 +$as_echo "$enable_python3interp" >&6; } +if test "$enable_python3interp" = "yes" -o "$enable_python3interp" = "dynamic"; then + if test "$has_eval" = "no"; then + as_fn_error $? "cannot use Python with tiny features" "$LINENO" 5 + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-python3-command argument" >&5 +$as_echo_n "checking --with-python3-command argument... " >&6; } + + +# Check whether --with-python3-command was given. +if test "${with_python3_command+set}" = set; then : + withval=$with_python3_command; vi_cv_path_python3="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3" >&5 +$as_echo "$vi_cv_path_python3" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "X$vi_cv_path_python3" = "X"; then + for ac_prog in python3 python +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_python3+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_python3 in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_python3="$vi_cv_path_python3" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_python3="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_python3=$ac_cv_path_vi_cv_path_python3 +if test -n "$vi_cv_path_python3"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3" >&5 +$as_echo "$vi_cv_path_python3" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$vi_cv_path_python3" && break +done + + fi + if test "X$vi_cv_path_python3" != "X"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python version" >&5 +$as_echo_n "checking Python version... " >&6; } +if ${vi_cv_var_python3_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_var_python3_version=` + ${vi_cv_path_python3} -c 'import sys; print("{}.{}".format(sys.version_info.major, sys.version_info.minor))'` + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_var_python3_version" >&5 +$as_echo "$vi_cv_var_python3_version" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python is 3.0 or better" >&5 +$as_echo_n "checking Python is 3.0 or better... " >&6; } + if ${vi_cv_path_python3} -c \ + "import sys; sys.exit(${vi_cv_var_python3_version} < 3.0)" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yep" >&5 +$as_echo "yep" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's abiflags" >&5 +$as_echo_n "checking Python's abiflags... " >&6; } +if ${vi_cv_var_python3_abiflags+:} false; then : + $as_echo_n "(cached) " >&6 +else + + vi_cv_var_python3_abiflags= + if ${vi_cv_path_python3} -c \ + "import sys; sys.exit(${vi_cv_var_python3_version} < 3.2)" + then + vi_cv_var_python3_abiflags=`${vi_cv_path_python3} -c \ + "import sys; print(sys.abiflags)"` + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_var_python3_abiflags" >&5 +$as_echo "$vi_cv_var_python3_abiflags" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's install prefix" >&5 +$as_echo_n "checking Python's install prefix... " >&6; } +if ${vi_cv_path_python3_pfx+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_path_python3_pfx=` + ${vi_cv_path_python3} -c \ + "import sys; print(sys.prefix)"` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3_pfx" >&5 +$as_echo "$vi_cv_path_python3_pfx" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's execution prefix" >&5 +$as_echo_n "checking Python's execution prefix... " >&6; } +if ${vi_cv_path_python3_epfx+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_path_python3_epfx=` + ${vi_cv_path_python3} -c \ + "import sys; print(sys.exec_prefix)"` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3_epfx" >&5 +$as_echo "$vi_cv_path_python3_epfx" >&6; } + + + if ${vi_cv_path_python3path+:} false; then : + $as_echo_n "(cached) " >&6 +else + vi_cv_path_python3path=` + unset PYTHONPATH; + ${vi_cv_path_python3} -c \ + "import sys, string; print(':'.join(sys.path))"` +fi + + + + +# Check whether --with-python3-config-dir was given. +if test "${with_python3_config_dir+set}" = set; then : + withval=$with_python3_config_dir; vi_cv_path_python3_conf="${withval}"; have_python3_config_dir=1 +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's configuration directory" >&5 +$as_echo_n "checking Python's configuration directory... " >&6; } +if ${vi_cv_path_python3_conf+:} false; then : + $as_echo_n "(cached) " >&6 +else + + vi_cv_path_python3_conf= + config_dir="config-${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}" + d=`${vi_cv_path_python3} -c "import sysconfig; print(sysconfig.get_config_var('LIBPL'))" 2> /dev/null` + if test "x$d" = "x"; then + d=`${vi_cv_path_python3} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBPL'))"` + fi + if test -d "$d" && test -f "$d/config.c"; then + vi_cv_path_python3_conf="$d" + else + for path in "${vi_cv_path_python3_pfx}" "${vi_cv_path_python3_epfx}"; do + for subdir in lib64 lib share; do + d="${path}/${subdir}/python${vi_cv_var_python3_version}/${config_dir}" + if test -d "$d" && test -f "$d/config.c"; then + vi_cv_path_python3_conf="$d" + fi + done + done + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3_conf" >&5 +$as_echo "$vi_cv_path_python3_conf" >&6; } + + PYTHON3_CONFDIR="${vi_cv_path_python3_conf}" + + if test "X$PYTHON3_CONFDIR" = "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: can't find it!" >&5 +$as_echo "can't find it!" >&6; } + else + + if ${vi_cv_path_python3_plibs+:} false; then : + $as_echo_n "(cached) " >&6 +else + + pwd=`pwd` + tmp_mkf="$pwd/config-PyMake$$" + cat -- "${PYTHON3_CONFDIR}/Makefile" - <<'eof' >"${tmp_mkf}" +__: + @echo "python3_BASEMODLIBS='$(BASEMODLIBS)'" + @echo "python3_LIBS='$(LIBS)'" + @echo "python3_SYSLIBS='$(SYSLIBS)'" + @echo "python3_DLLLIBRARY='$(DLLLIBRARY)'" + @echo "python3_INSTSONAME='$(INSTSONAME)'" +eof + eval "`cd ${PYTHON3_CONFDIR} && make -f "${tmp_mkf}" __ | sed '/ directory /d'`" + rm -f -- "${tmp_mkf}" + vi_cv_path_python3_plibs="-L${PYTHON3_CONFDIR} -lpython${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}" + vi_cv_path_python3_plibs="${vi_cv_path_python3_plibs} ${python3_BASEMODLIBS} ${python3_LIBS} ${python3_SYSLIBS}" + vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-ltermcap//` + vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-lffi//` + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python3's dll name" >&5 +$as_echo_n "checking Python3's dll name... " >&6; } +if ${vi_cv_dll_name_python3+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "X$python3_DLLLIBRARY" != "X"; then + vi_cv_dll_name_python3="$python3_DLLLIBRARY" + else + vi_cv_dll_name_python3="$python3_INSTSONAME" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_dll_name_python3" >&5 +$as_echo "$vi_cv_dll_name_python3" >&6; } + + PYTHON3_LIBS="${vi_cv_path_python3_plibs}" + if test "${vi_cv_path_python3_pfx}" = "${vi_cv_path_python3_epfx}"; then + PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}" + else + PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags} -I${vi_cv_path_python3_epfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}" + fi + if test "X$have_python3_config_dir" = "X1" -a "$enable_python3interp" = "dynamic"; then + PYTHON3_CFLAGS="${PYTHON3_CFLAGS} -DPYTHON3_HOME='L\"${vi_cv_path_python3_pfx}\"'" + fi + PYTHON3_SRC="if_python3.c" + PYTHON3_OBJ="objects/if_python3.o" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -pthread should be used" >&5 +$as_echo_n "checking if -pthread should be used... " >&6; } + threadsafe_flag= + thread_lib= + if test "$vim_cv_uname_output" != Darwin; then + test "$GCC" = yes && threadsafe_flag="-pthread" + if test "$vim_cv_uname_output" = FreeBSD; then + threadsafe_flag="-D_THREAD_SAFE" + thread_lib="-pthread" + fi + if test "$vim_cv_uname_output" = SunOS; then + threadsafe_flag="-pthreads" + fi + fi + libs_save_old=$LIBS + if test -n "$threadsafe_flag"; then + cflags_save=$CFLAGS + CFLAGS="$CFLAGS $threadsafe_flag" + LIBS="$LIBS $thread_lib" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; PYTHON3_CFLAGS="$PYTHON3_CFLAGS $threadsafe_flag" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; LIBS=$libs_save_old + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$cflags_save + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compile and link flags for Python 3 are sane" >&5 +$as_echo_n "checking if compile and link flags for Python 3 are sane... " >&6; } + cflags_save=$CFLAGS + libs_save=$LIBS + CFLAGS="$CFLAGS $PYTHON3_CFLAGS" + LIBS="$LIBS $PYTHON3_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; python3_ok=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no: PYTHON3 DISABLED" >&5 +$as_echo "no: PYTHON3 DISABLED" >&6; }; python3_ok=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$cflags_save + LIBS=$libs_save + if test "$python3_ok" = yes; then + $as_echo "#define FEAT_PYTHON3 1" >>confdefs.h + + else + LIBS=$libs_save_old + PYTHON3_SRC= + PYTHON3_OBJ= + PYTHON3_LIBS= + PYTHON3_CFLAGS= + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: too old" >&5 +$as_echo "too old" >&6; } + fi + fi + if test "$fail_if_missing" = "yes" -a "$python3_ok" != "yes"; then + as_fn_error $? "could not configure python3" "$LINENO" 5 + fi +fi + + + + + + + +if test "$python_ok" = yes && test "$python3_ok" = yes; then + $as_echo "#define DYNAMIC_PYTHON 1" >>confdefs.h + + $as_echo "#define DYNAMIC_PYTHON3 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can do without RTLD_GLOBAL for Python" >&5 +$as_echo_n "checking whether we can do without RTLD_GLOBAL for Python... " >&6; } + cflags_save=$CFLAGS + CFLAGS="$CFLAGS $PYTHON_CFLAGS" + libs_save=$LIBS + LIBS="-ldl $LIBS" + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + /* If this program fails, then RTLD_GLOBAL is needed. + * RTLD_GLOBAL will be used and then it is not possible to + * have both python versions enabled in the same vim instance. + * Only the first python version used will be switched on. + */ + + static int no_rtl_global_needed_for(char *python_instsoname, char *prefix) + { + int needed = 0; + void* pylib = dlopen(python_instsoname, RTLD_LAZY|RTLD_LOCAL); + if (pylib != 0) + { + void (*pfx)(char *home) = dlsym(pylib, "Py_SetPythonHome"); + void (*init)(void) = dlsym(pylib, "Py_Initialize"); + int (*simple)(char*) = dlsym(pylib, "PyRun_SimpleString"); + void (*final)(void) = dlsym(pylib, "Py_Finalize"); + (*pfx)(prefix); + (*init)(); + needed = (*simple)("import termios") == -1; + (*final)(); + dlclose(pylib); + } + return !needed; + } + + int main() + { + int not_needed = 0; + if (no_rtl_global_needed_for("${vi_cv_dll_name_python}", "${vi_cv_path_python_pfx}")) + not_needed = 1; + return !not_needed; + } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; };$as_echo "#define PY_NO_RTLD_GLOBAL 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + + CFLAGS=$cflags_save + LIBS=$libs_save + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can do without RTLD_GLOBAL for Python3" >&5 +$as_echo_n "checking whether we can do without RTLD_GLOBAL for Python3... " >&6; } + cflags_save=$CFLAGS + CFLAGS="$CFLAGS $PYTHON3_CFLAGS" + libs_save=$LIBS + LIBS="-ldl $LIBS" + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + /* If this program fails, then RTLD_GLOBAL is needed. + * RTLD_GLOBAL will be used and then it is not possible to + * have both python versions enabled in the same vim instance. + * Only the first python version used will be switched on. + */ + + static int no_rtl_global_needed_for(char *python_instsoname, wchar_t *prefix) + { + int needed = 0; + void* pylib = dlopen(python_instsoname, RTLD_LAZY|RTLD_LOCAL); + if (pylib != 0) + { + void (*pfx)(wchar_t *home) = dlsym(pylib, "Py_SetPythonHome"); + void (*init)(void) = dlsym(pylib, "Py_Initialize"); + int (*simple)(char*) = dlsym(pylib, "PyRun_SimpleString"); + void (*final)(void) = dlsym(pylib, "Py_Finalize"); + (*pfx)(prefix); + (*init)(); + needed = (*simple)("import termios") == -1; + (*final)(); + dlclose(pylib); + } + return !needed; + } + + int main() + { + int not_needed = 0; + if (no_rtl_global_needed_for("${vi_cv_dll_name_python3}", L"${vi_cv_path_python3_pfx}")) + not_needed = 1; + return !not_needed; + } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; };$as_echo "#define PY3_NO_RTLD_GLOBAL 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + + CFLAGS=$cflags_save + LIBS=$libs_save + + PYTHON_SRC="if_python.c" + PYTHON_OBJ="objects/if_python.o" + PYTHON_CFLAGS="$PYTHON_CFLAGS -DDYNAMIC_PYTHON_DLL=\\\"${vi_cv_dll_name_python}\\\"" + PYTHON_LIBS= + PYTHON3_SRC="if_python3.c" + PYTHON3_OBJ="objects/if_python3.o" + PYTHON3_CFLAGS="$PYTHON3_CFLAGS -DDYNAMIC_PYTHON3_DLL=\\\"${vi_cv_dll_name_python3}\\\"" + PYTHON3_LIBS= +elif test "$python_ok" = yes && test "$enable_pythoninterp" = "dynamic"; then + $as_echo "#define DYNAMIC_PYTHON 1" >>confdefs.h + + PYTHON_SRC="if_python.c" + PYTHON_OBJ="objects/if_python.o" + PYTHON_CFLAGS="$PYTHON_CFLAGS -DDYNAMIC_PYTHON_DLL=\\\"${vi_cv_dll_name_python}\\\"" + PYTHON_LIBS= +elif test "$python_ok" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -fPIE can be added for Python" >&5 +$as_echo_n "checking if -fPIE can be added for Python... " >&6; } + cflags_save=$CFLAGS + libs_save=$LIBS + CFLAGS="$CFLAGS $PYTHON_CFLAGS -fPIE" + LIBS="$LIBS $PYTHON_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; fpie_ok=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; fpie_ok=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$cflags_save + LIBS=$libs_save + if test $fpie_ok = yes; then + PYTHON_CFLAGS="$PYTHON_CFLAGS -fPIE" + fi +elif test "$python3_ok" = yes && test "$enable_python3interp" = "dynamic"; then + $as_echo "#define DYNAMIC_PYTHON3 1" >>confdefs.h + + PYTHON3_SRC="if_python3.c" + PYTHON3_OBJ="objects/if_python3.o" + PYTHON3_CFLAGS="$PYTHON3_CFLAGS -DDYNAMIC_PYTHON3_DLL=\\\"${vi_cv_dll_name_python3}\\\"" + PYTHON3_LIBS= +elif test "$python3_ok" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -fPIE can be added for Python3" >&5 +$as_echo_n "checking if -fPIE can be added for Python3... " >&6; } + cflags_save=$CFLAGS + libs_save=$LIBS + CFLAGS="$CFLAGS $PYTHON3_CFLAGS -fPIE" + LIBS="$LIBS $PYTHON3_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; fpie_ok=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; fpie_ok=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$cflags_save + LIBS=$libs_save + if test $fpie_ok = yes; then + PYTHON3_CFLAGS="$PYTHON3_CFLAGS -fPIE" + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-tclinterp argument" >&5 +$as_echo_n "checking --enable-tclinterp argument... " >&6; } +# Check whether --enable-tclinterp was given. +if test "${enable_tclinterp+set}" = set; then : + enableval=$enable_tclinterp; +else + enable_tclinterp="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tclinterp" >&5 +$as_echo "$enable_tclinterp" >&6; } + +if test "$enable_tclinterp" = "yes" -o "$enable_tclinterp" = "dynamic"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-tclsh argument" >&5 +$as_echo_n "checking --with-tclsh argument... " >&6; } + +# Check whether --with-tclsh was given. +if test "${with_tclsh+set}" = set; then : + withval=$with_tclsh; tclsh_name="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tclsh_name" >&5 +$as_echo "$tclsh_name" >&6; } +else + tclsh_name="tclsh8.5"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + # Extract the first word of "$tclsh_name", so it can be a program name with args. +set dummy $tclsh_name; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_tcl+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_tcl in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_tcl="$vi_cv_path_tcl" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_tcl="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_tcl=$ac_cv_path_vi_cv_path_tcl +if test -n "$vi_cv_path_tcl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_tcl" >&5 +$as_echo "$vi_cv_path_tcl" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.5"; then + tclsh_name="tclsh8.4" + # Extract the first word of "$tclsh_name", so it can be a program name with args. +set dummy $tclsh_name; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_tcl+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_tcl in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_tcl="$vi_cv_path_tcl" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_tcl="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_tcl=$ac_cv_path_vi_cv_path_tcl +if test -n "$vi_cv_path_tcl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_tcl" >&5 +$as_echo "$vi_cv_path_tcl" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.4"; then + tclsh_name="tclsh8.2" + # Extract the first word of "$tclsh_name", so it can be a program name with args. +set dummy $tclsh_name; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_tcl+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_tcl in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_tcl="$vi_cv_path_tcl" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_tcl="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_tcl=$ac_cv_path_vi_cv_path_tcl +if test -n "$vi_cv_path_tcl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_tcl" >&5 +$as_echo "$vi_cv_path_tcl" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.2"; then + tclsh_name="tclsh8.0" + # Extract the first word of "$tclsh_name", so it can be a program name with args. +set dummy $tclsh_name; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_tcl+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_tcl in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_tcl="$vi_cv_path_tcl" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_tcl="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_tcl=$ac_cv_path_vi_cv_path_tcl +if test -n "$vi_cv_path_tcl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_tcl" >&5 +$as_echo "$vi_cv_path_tcl" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + if test "X$vi_cv_path_tcl" = "X"; then + tclsh_name="tclsh" + # Extract the first word of "$tclsh_name", so it can be a program name with args. +set dummy $tclsh_name; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_tcl+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_tcl in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_tcl="$vi_cv_path_tcl" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_tcl="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_tcl=$ac_cv_path_vi_cv_path_tcl +if test -n "$vi_cv_path_tcl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_tcl" >&5 +$as_echo "$vi_cv_path_tcl" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + if test "X$vi_cv_path_tcl" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Tcl version" >&5 +$as_echo_n "checking Tcl version... " >&6; } + if echo 'exit [expr [info tclversion] < 8.0]' | "$vi_cv_path_tcl" - ; then + tclver=`echo 'puts [info tclversion]' | $vi_cv_path_tcl -` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tclver - OK" >&5 +$as_echo "$tclver - OK" >&6; }; + tclloc=`echo 'set l [info library];set i [string last lib $l];incr i -2;puts [string range $l 0 $i]' | $vi_cv_path_tcl -` + tcldll=`echo 'puts libtcl[info tclversion][info sharedlibextension]' | $vi_cv_path_tcl -` + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of Tcl include" >&5 +$as_echo_n "checking for location of Tcl include... " >&6; } + if test "x$MACOS_X" != "xyes"; then + tclinc="$tclloc/include $tclloc/include/tcl $tclloc/include/tcl$tclver /usr/local/include /usr/local/include/tcl$tclver /usr/include /usr/include/tcl$tclver" + else + tclinc="$tclloc/include $tclloc/include/tcl $tclloc/include/tcl$tclver /System/Library/Frameworks/Tcl.framework/Headers `xcrun --show-sdk-path`/System/Library/Frameworks/Tcl.framework/Versions/Current/Headers" + fi + TCL_INC= + for try in $tclinc; do + if test -f "$try/tcl.h"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $try/tcl.h" >&5 +$as_echo "$try/tcl.h" >&6; } + TCL_INC=$try + break + fi + done + if test -z "$TCL_INC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 +$as_echo "" >&6; } + SKIP_TCL=YES + fi + if test -z "$SKIP_TCL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of tclConfig.sh script" >&5 +$as_echo_n "checking for location of tclConfig.sh script... " >&6; } + if test "x$MACOS_X" != "xyes"; then + tclcnf=`echo $tclinc | sed s/include/lib/g` + tclcnf="$tclcnf `echo $tclinc | sed s/include/lib64/g`" + else + tclcnf=`echo $tclinc | sed s/include/lib/g` + tclcnf="$tclcnf /System/Library/Frameworks/Tcl.framework `xcrun --show-sdk-path`/System/Library/Frameworks/Tcl.framework" + fi + for try in $tclcnf; do + if test -f "$try/tclConfig.sh"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $try/tclConfig.sh" >&5 +$as_echo "$try/tclConfig.sh" >&6; } + . "$try/tclConfig.sh" + if test "$enable_tclinterp" = "dynamic"; then + TCL_LIBS=`eval echo "$TCL_STUB_LIB_SPEC $TCL_LIBS"` + else + TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"` + fi + TCL_DEFS=`echo $TCL_DEFS | sed -e 's/\\\\ /\\\\X/g' | tr ' ' '\012' | sed -e '/^[^-]/d' -e '/^-[^D]/d' -e '/-D[^_]/d' -e 's/-D_/ -D_/' | tr '\012' ' ' | sed -e 's/\\\\X/\\\\ /g'` + break + fi + done + if test -z "$TCL_LIBS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 +$as_echo "" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl library by myself" >&5 +$as_echo_n "checking for Tcl library by myself... " >&6; } + tcllib=`echo $tclinc | sed s/include/lib/g` + tcllib="$tcllib `echo $tclinc | sed s/include/lib64/g`" + for ext in .so .a ; do + for ver in "" $tclver ; do + for try in $tcllib ; do + trylib=tcl$ver$ext + if test -f "$try/lib$trylib" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $try/lib$trylib" >&5 +$as_echo "$try/lib$trylib" >&6; } + TCL_LIBS="-L\"$try\" -ltcl$ver -ldl -lm" + if test "$vim_cv_uname_output" = SunOS && + echo $vim_cv_uname_r_output | grep '^5' >/dev/null; then + TCL_LIBS="$TCL_LIBS -R $try" + fi + break 3 + fi + done + done + done + if test -z "$TCL_LIBS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 +$as_echo "" >&6; } + SKIP_TCL=YES + fi + fi + if test -z "$SKIP_TCL"; then + $as_echo "#define FEAT_TCL 1" >>confdefs.h + + TCL_SRC=if_tcl.c + TCL_OBJ=objects/if_tcl.o + TCL_PRO=if_tcl.pro + TCL_CFLAGS="-I$TCL_INC $TCL_DEFS" + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: too old; need Tcl version 8.0 or later" >&5 +$as_echo "too old; need Tcl version 8.0 or later" >&6; } + fi + fi + if test "$enable_tclinterp" = "dynamic"; then + if test "X$TCL_SRC" != "X" -a "X$tcldll" != "X"; then + $as_echo "#define DYNAMIC_TCL 1" >>confdefs.h + + TCL_CFLAGS="-DDYNAMIC_TCL_DLL=\\\"$tcldll\\\" -DDYNAMIC_TCL_VER=\\\"$tclver\\\" $TCL_CFLAGS" + fi + fi + if test "$fail_if_missing" = "yes" -a -z "$TCL_SRC"; then + as_fn_error $? "could not configure Tcl" "$LINENO" 5 + fi +fi + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-rubyinterp argument" >&5 +$as_echo_n "checking --enable-rubyinterp argument... " >&6; } +# Check whether --enable-rubyinterp was given. +if test "${enable_rubyinterp+set}" = set; then : + enableval=$enable_rubyinterp; +else + enable_rubyinterp="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_rubyinterp" >&5 +$as_echo "$enable_rubyinterp" >&6; } +if test "$enable_rubyinterp" = "yes" -o "$enable_rubyinterp" = "dynamic"; then + if test "$has_eval" = "no"; then + as_fn_error $? "cannot use Ruby with tiny features" "$LINENO" 5 + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-ruby-command argument" >&5 +$as_echo_n "checking --with-ruby-command argument... " >&6; } + + +# Check whether --with-ruby-command was given. +if test "${with_ruby_command+set}" = set; then : + withval=$with_ruby_command; RUBY_CMD="$withval"; vi_cv_path_ruby="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_CMD" >&5 +$as_echo "$RUBY_CMD" >&6; } +else + RUBY_CMD="ruby"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to $RUBY_CMD" >&5 +$as_echo "defaulting to $RUBY_CMD" >&6; } +fi + + # Extract the first word of "$RUBY_CMD", so it can be a program name with args. +set dummy $RUBY_CMD; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_vi_cv_path_ruby+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $vi_cv_path_ruby in + [\\/]* | ?:[\\/]*) + ac_cv_path_vi_cv_path_ruby="$vi_cv_path_ruby" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_vi_cv_path_ruby="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +vi_cv_path_ruby=$ac_cv_path_vi_cv_path_ruby +if test -n "$vi_cv_path_ruby"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_ruby" >&5 +$as_echo "$vi_cv_path_ruby" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "X$vi_cv_path_ruby" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Ruby version" >&5 +$as_echo_n "checking Ruby version... " >&6; } + if $vi_cv_path_ruby -e 'RUBY_VERSION >= "1.9.1" or exit 1' >/dev/null 2>/dev/null; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK" >&5 +$as_echo "OK" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Ruby rbconfig" >&5 +$as_echo_n "checking Ruby rbconfig... " >&6; } + ruby_rbconfig="RbConfig" + if ! $vi_cv_path_ruby -r rbconfig -e 'RbConfig' >/dev/null 2>/dev/null; then + ruby_rbconfig="Config" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ruby_rbconfig" >&5 +$as_echo "$ruby_rbconfig" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Ruby header files" >&5 +$as_echo_n "checking Ruby header files... " >&6; } + rubyhdrdir=`$vi_cv_path_ruby -r mkmf -e "print $ruby_rbconfig::CONFIG['rubyhdrdir'] || $ruby_rbconfig::CONFIG['archdir'] || \\$hdrdir" 2>/dev/null` + if test "X$rubyhdrdir" != "X"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rubyhdrdir" >&5 +$as_echo "$rubyhdrdir" >&6; } + RUBY_CFLAGS="-I$rubyhdrdir" + rubyarchdir=`$vi_cv_path_ruby -r rbconfig -e "print ($ruby_rbconfig::CONFIG.has_key? 'rubyarchhdrdir') ? $ruby_rbconfig::CONFIG['rubyarchhdrdir'] : '$rubyhdrdir/'+$ruby_rbconfig::CONFIG['arch']"` + if test -d "$rubyarchdir"; then + RUBY_CFLAGS="$RUBY_CFLAGS -I$rubyarchdir" + fi + rubyversion=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig::CONFIG['ruby_version'].gsub(/\./, '')[0,2]"` + if test "X$rubyversion" = "X"; then + rubyversion=`$vi_cv_path_ruby -e "print RUBY_VERSION.gsub(/\./, '')[0,2]"` + fi + RUBY_CFLAGS="$RUBY_CFLAGS -DRUBY_VERSION=$rubyversion" + rubylibs=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig::CONFIG['LIBS']"` + if test "X$rubylibs" != "X"; then + RUBY_LIBS="$rubylibs" + fi + librubyarg=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG['LIBRUBYARG'])"` + librubya=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG['LIBRUBY_A'])"` + rubylibdir=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG['libdir'])"` + if test -f "$rubylibdir/$librubya" || expr "$librubyarg" : "-lruby"; then + RUBY_LIBS="$RUBY_LIBS -L$rubylibdir" + elif test "$librubyarg" = "libruby.a"; then + librubyarg="-lruby" + RUBY_LIBS="$RUBY_LIBS -L$rubylibdir" + fi + + if test "X$librubyarg" != "X"; then + RUBY_LIBS="$librubyarg $RUBY_LIBS" + fi + + + RUBY_SRC="if_ruby.c" + RUBY_OBJ="objects/if_ruby.o" + RUBY_PRO="if_ruby.pro" + $as_echo "#define FEAT_RUBY 1" >>confdefs.h + + if test "$enable_rubyinterp" = "dynamic"; then + libruby_soname=`$vi_cv_path_ruby -r rbconfig -e "puts $ruby_rbconfig::CONFIG['LIBRUBY_ALIASES'].split[0]"` + if test -z "$libruby_soname"; then + libruby_soname=`$vi_cv_path_ruby -r rbconfig -e "puts $ruby_rbconfig::CONFIG['LIBRUBY_SO']"` + fi + $as_echo "#define DYNAMIC_RUBY 1" >>confdefs.h + + RUBY_CFLAGS="-DDYNAMIC_RUBY_DLL=\\\"$libruby_soname\\\" $RUBY_CFLAGS" + RUBY_LIBS= + fi + if test "X$CLANG_VERSION" != "X" -a "$rubyversion" -ge 30; then + RUBY_CFLAGS="$RUBY_CFLAGS -fdeclspec" + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found; disabling Ruby" >&5 +$as_echo "not found; disabling Ruby" >&6; } + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: too old; need Ruby version 1.9.1 or later" >&5 +$as_echo "too old; need Ruby version 1.9.1 or later" >&6; } + fi + fi + + if test "$fail_if_missing" = "yes" -a -z "$RUBY_OBJ"; then + as_fn_error $? "could not configure Ruby" "$LINENO" 5 + fi +fi + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-cscope argument" >&5 +$as_echo_n "checking --enable-cscope argument... " >&6; } +# Check whether --enable-cscope was given. +if test "${enable_cscope+set}" = set; then : + enableval=$enable_cscope; +else + enable_cscope="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_cscope" >&5 +$as_echo "$enable_cscope" >&6; } +if test "$enable_cscope" = "yes"; then + $as_echo "#define FEAT_CSCOPE 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-netbeans argument" >&5 +$as_echo_n "checking --disable-netbeans argument... " >&6; } +# Check whether --enable-netbeans was given. +if test "${enable_netbeans+set}" = set; then : + enableval=$enable_netbeans; +else + enable_netbeans="yes" +fi + +if test "$enable_netbeans" = "yes"; then + if test "$has_eval" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot use NetBeans with tiny features" >&5 +$as_echo "cannot use NetBeans with tiny features" >&6; } + enable_netbeans="no" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-channel argument" >&5 +$as_echo_n "checking --disable-channel argument... " >&6; } +# Check whether --enable-channel was given. +if test "${enable_channel+set}" = set; then : + enableval=$enable_channel; +else + enable_channel="yes" +fi + +if test "$enable_channel" = "yes"; then + if test "$has_eval" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot use channels with tiny features" >&5 +$as_echo "cannot use channels with tiny features" >&6; } + enable_channel="no" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi +else + if test "$enable_netbeans" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, netbeans also disabled" >&5 +$as_echo "yes, netbeans also disabled" >&6; } + enable_netbeans="no" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi +fi + +if test "$enable_channel" = "yes"; then + if test "x$HAIKU" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5 +$as_echo_n "checking for socket in -lnetwork... " >&6; } +if ${ac_cv_lib_network_socket+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnetwork $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char socket (); +int +main () +{ +return socket (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_network_socket=yes +else + ac_cv_lib_network_socket=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_socket" >&5 +$as_echo "$ac_cv_lib_network_socket" >&6; } +if test "x$ac_cv_lib_network_socket" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNETWORK 1 +_ACEOF + + LIBS="-lnetwork $LIBS" + +fi + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 +$as_echo_n "checking for socket in -lsocket... " >&6; } +if ${ac_cv_lib_socket_socket+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char socket (); +int +main () +{ +return socket (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_socket=yes +else + ac_cv_lib_socket_socket=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 +$as_echo "$ac_cv_lib_socket_socket" >&6; } +if test "x$ac_cv_lib_socket_socket" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling with IPv6 networking is possible" >&5 +$as_echo_n "checking whether compiling with IPv6 networking is possible... " >&6; } +if ${vim_cv_ipv6_networking+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + /* Check bitfields */ + struct nbbuf { + unsigned int initDone:1; + unsigned short signmaplen; + }; + +int +main () +{ + + /* Check creating a socket. */ + struct sockaddr_in server; + struct addrinfo *res; + (void)socket(AF_INET, SOCK_STREAM, 0); + (void)htons(100); + (void)getaddrinfo("microsoft.com", NULL, NULL, &res); + if (errno == ECONNREFUSED) + (void)connect(1, (struct sockaddr *)&server, sizeof(server)); + (void)freeaddrinfo(res); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + vim_cv_ipv6_networking="yes" +else + vim_cv_ipv6_networking="no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_ipv6_networking" >&5 +$as_echo "$vim_cv_ipv6_networking" >&6; } + + if test "x$vim_cv_ipv6_networking" = "xyes"; then + $as_echo "#define FEAT_IPV6 1" >>confdefs.h + + for ac_func in inet_ntop +do : + ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop" +if test "x$ac_cv_func_inet_ntop" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_INET_NTOP 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if ${ac_cv_lib_nsl_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nsl_gethostbyname=yes +else + ac_cv_lib_nsl_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling with IPv4 networking is possible" >&5 +$as_echo_n "checking whether compiling with IPv4 networking is possible... " >&6; } +if ${vim_cv_ipv4_networking+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + /* Check bitfields */ + struct nbbuf { + unsigned int initDone:1; + unsigned short signmaplen; + }; + +int +main () +{ + + /* Check creating a socket. */ + struct sockaddr_in server; + (void)socket(AF_INET, SOCK_STREAM, 0); + (void)htons(100); + (void)gethostbyname("microsoft.com"); + if (errno == ECONNREFUSED) + (void)connect(1, (struct sockaddr *)&server, sizeof(server)); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + vim_cv_ipv4_networking="yes" +else + vim_cv_ipv4_networking="no"; enable_netbeans="no"; enable_channel="no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_ipv4_networking" >&5 +$as_echo "$vim_cv_ipv4_networking" >&6; } + fi +fi +if test "$enable_netbeans" = "yes"; then + $as_echo "#define FEAT_NETBEANS_INTG 1" >>confdefs.h + + NETBEANS_SRC="netbeans.c" + + NETBEANS_OBJ="objects/netbeans.o" + +fi +if test "$enable_channel" = "yes"; then + $as_echo "#define FEAT_JOB_CHANNEL 1" >>confdefs.h + + CHANNEL_SRC="job.c channel.c" + + CHANNEL_OBJ="objects/job.o objects/channel.o" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-terminal argument" >&5 +$as_echo_n "checking --enable-terminal argument... " >&6; } +# Check whether --enable-terminal was given. +if test "${enable_terminal+set}" = set; then : + enableval=$enable_terminal; +else + enable_terminal="auto" +fi + +if test "$enable_terminal" = "yes" || test "$enable_terminal" = "auto" -a "x$features" = "xhuge" ; then + if test "$has_eval" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot use terminal emulator with tiny features" >&5 +$as_echo "cannot use terminal emulator with tiny features" >&6; } + enable_terminal="no" + else + if test "$enable_terminal" = "auto"; then + enable_terminal="yes" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to yes" >&5 +$as_echo "defaulting to yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + fi +else + if test "$enable_terminal" = "auto"; then + enable_terminal="no" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to no" >&5 +$as_echo "defaulting to no" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi +fi +if test "$enable_terminal" = "yes" -a "$enable_channel" = "yes"; then + $as_echo "#define FEAT_TERMINAL 1" >>confdefs.h + + TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/creen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c" + + TERM_OBJ="objects/vterm_encoding.o objects/vterm_keyboard.o objects/vterm_mouse.o objects/vterm_parser.o objects/vterm_pen.o objects/vterm_screen.o objects/vterm_state.o objects/vterm_unicode.o objects/vterm_vterm.o" + + TERM_TEST="test_libvterm" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-autoservername argument" >&5 +$as_echo_n "checking --enable-autoservername argument... " >&6; } +# Check whether --enable-autoservername was given. +if test "${enable_autoservername+set}" = set; then : + enableval=$enable_autoservername; +else + enable_autoservername="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_autoservername" >&5 +$as_echo "$enable_autoservername" >&6; } +if test "$enable_autoservername" = "yes"; then + $as_echo "#define FEAT_AUTOSERVERNAME 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-multibyte argument" >&5 +$as_echo_n "checking --enable-multibyte argument... " >&6; } +# Check whether --enable-multibyte was given. +if test "${enable_multibyte+set}" = set; then : + enableval=$enable_multibyte; +else + enable_multibyte="yes" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_multibyte" >&5 +$as_echo "$enable_multibyte" >&6; } +if test "$enable_multibyte" != "yes"; then + as_fn_error $? "The multi-byte feature can no longer be disabled. If you have + a problem with this, discuss on the Vim mailing list." "$LINENO" 5 +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-rightleft argument" >&5 +$as_echo_n "checking --disable-rightleft argument... " >&6; } +# Check whether --enable-rightleft was given. +if test "${enable_rightleft+set}" = set; then : + enableval=$enable_rightleft; +else + enable_rightleft="yes" +fi + +if test "$enable_rightleft" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define DISABLE_RIGHTLEFT 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-arabic argument" >&5 +$as_echo_n "checking --disable-arabic argument... " >&6; } +# Check whether --enable-arabic was given. +if test "${enable_arabic+set}" = set; then : + enableval=$enable_arabic; +else + enable_arabic="yes" +fi + +if test "$enable_arabic" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define DISABLE_ARABIC 1" >>confdefs.h + +fi + +# Check whether --enable-farsi was given. +if test "${enable_farsi+set}" = set; then : + enableval=$enable_farsi; +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-xim argument" >&5 +$as_echo_n "checking --enable-xim argument... " >&6; } +# Check whether --enable-xim was given. +if test "${enable_xim+set}" = set; then : + enableval=$enable_xim; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_xim" >&5 +$as_echo "$enable_xim" >&6; } +else + enable_xim="auto"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to auto" >&5 +$as_echo "defaulting to auto" >&6; } +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-fontset argument" >&5 +$as_echo_n "checking --enable-fontset argument... " >&6; } +# Check whether --enable-fontset was given. +if test "${enable_fontset+set}" = set; then : + enableval=$enable_fontset; +else + enable_fontset="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_fontset" >&5 +$as_echo "$enable_fontset" >&6; } + +test -z "$with_x" && with_x=yes +test "${enable_gui-yes}" != no -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && with_x=yes +if test "$with_x" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to: don't HAVE_X11" >&5 +$as_echo "defaulting to: don't HAVE_X11" >&6; } +else + + # Extract the first word of "xmkmf", so it can be a program name with args. +set dummy xmkmf; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_xmkmfpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $xmkmfpath in + [\\/]* | ?:[\\/]*) + ac_cv_path_xmkmfpath="$xmkmfpath" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_xmkmfpath="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +xmkmfpath=$ac_cv_path_xmkmfpath +if test -n "$xmkmfpath"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xmkmfpath" >&5 +$as_echo "$xmkmfpath" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 +$as_echo_n "checking for X... " >&6; } + + +# Check whether --with-x was given. +if test "${with_x+set}" = set; then : + withval=$with_x; +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + case $x_includes,$x_libraries in #( + *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( + *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : + $as_echo_n "(cached) " >&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=no ac_x_libraries=no +rm -f -r conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + cat >Imakefile <<'_ACEOF' +incroot: + @echo incroot='${INCROOT}' +usrlibdir: + @echo usrlibdir='${USRLIBDIR}' +libdir: + @echo libdir='${LIBDIR}' +_ACEOF + if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. + for ac_var in incroot usrlibdir libdir; do + eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" + done + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl dylib la dll; do + if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && + test -f "$ac_im_libdir/libX11.$ac_extension"; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case $ac_im_incroot in + /usr/include) ac_x_includes= ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /usr/lib64 | /lib | /lib64) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -f -r conftest.dir +fi + +# Standard set of common directories for X headers. +# Check X11 before X11Rn because it is often a symlink to the current release. +ac_x_header_dirs=' +/usr/X11/include +/usr/X11R7/include +/usr/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R7 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R7/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/usr/local/include/X11R7 +/usr/local/include/X11R6 +/usr/local/include/X11R5 +/usr/local/include/X11R4 + +/usr/X386/include +/usr/x386/include +/usr/XFree86/include/X11 + +/usr/include +/usr/local/include +/usr/unsupported/include +/usr/athena/include +/usr/local/x11r5/include +/usr/lpp/Xamples/include + +/usr/openwin/include +/usr/openwin/share/include' + +if test "$ac_x_includes" = no; then + # Guess where to find include files, by looking for Xlib.h. + # First, try using that file with no special directory specified. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # We can compile using X headers with no special include directory. +ac_x_includes= +else + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Xlib.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi +rm -f conftest.err conftest.i conftest.$ac_ext +fi # $ac_x_includes = no + +if test "$ac_x_libraries" = no; then + # Check for the libraries. + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS=$LIBS + LIBS="-lX11 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +XrmInitialize () + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + LIBS=$ac_save_LIBS +for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +do + # Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl dylib la dll; do + if test -r "$ac_dir/libX11.$ac_extension"; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +case $ac_x_includes,$ac_x_libraries in #( + no,* | *,no | *\'*) + # Didn't find X, or a directory has "'" in its name. + ac_cv_have_x="have_x=no";; #( + *) + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$ac_x_includes'\ + ac_x_libraries='$ac_x_libraries'" +esac +fi +;; #( + *) have_x=yes;; + esac + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 +$as_echo "$have_x" >&6; } + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$x_includes'\ + ac_x_libraries='$x_libraries'" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 +$as_echo "libraries $x_libraries, headers $x_includes" >&6; } +fi + +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + +$as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h + + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 +$as_echo_n "checking whether -R must be followed by a space... " >&6; } + ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" + ac_xsave_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + X_LIBS="$X_LIBS -R$x_libraries" +else + LIBS="$ac_xsave_LIBS -R $x_libraries" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + X_LIBS="$X_LIBS -R $x_libraries" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 +$as_echo "neither works" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_c_werror_flag=$ac_xsave_c_werror_flag + LIBS=$ac_xsave_LIBS + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn Johnson says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And Karl Berry says + # the Alpha needs dnet_stub (dnet does not exist). + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XOpenDisplay (); +int +main () +{ +return XOpenDisplay (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } +if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dnet_dnet_ntoa=yes +else + ac_cv_lib_dnet_dnet_ntoa=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" +fi + + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } +if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet_stub $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dnet_stub_dnet_ntoa=yes +else + ac_cv_lib_dnet_stub_dnet_ntoa=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" +fi + + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_xsave_LIBS" + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to T.E. Dickey. + # The functions gethostbyname, getservbyname, and inet_addr are + # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. + ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" +if test "x$ac_cv_func_gethostbyname" = xyes; then : + +fi + + if test $ac_cv_func_gethostbyname = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if ${ac_cv_lib_nsl_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nsl_gethostbyname=yes +else + ac_cv_lib_nsl_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" +fi + + if test $ac_cv_lib_nsl_gethostbyname = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 +$as_echo_n "checking for gethostbyname in -lbsd... " >&6; } +if ${ac_cv_lib_bsd_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_bsd_gethostbyname=yes +else + ac_cv_lib_bsd_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 +$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } +if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" +fi + + fi + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says Simon Leinen: it contains gethostby* + # variants that don't use the name server (or something). -lsocket + # must be given before -lnsl if both are needed. We assume that + # if connect needs -lnsl, so does gethostbyname. + ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" +if test "x$ac_cv_func_connect" = xyes; then : + +fi + + if test $ac_cv_func_connect = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 +$as_echo_n "checking for connect in -lsocket... " >&6; } +if ${ac_cv_lib_socket_connect+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char connect (); +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_connect=yes +else + ac_cv_lib_socket_connect=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 +$as_echo "$ac_cv_lib_socket_connect" >&6; } +if test "x$ac_cv_lib_socket_connect" = xyes; then : + X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" +fi + + fi + + # Guillermo Gomez says -lposix is necessary on A/UX. + ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" +if test "x$ac_cv_func_remove" = xyes; then : + +fi + + if test $ac_cv_func_remove = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 +$as_echo_n "checking for remove in -lposix... " >&6; } +if ${ac_cv_lib_posix_remove+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lposix $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char remove (); +int +main () +{ +return remove (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_posix_remove=yes +else + ac_cv_lib_posix_remove=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 +$as_echo "$ac_cv_lib_posix_remove" >&6; } +if test "x$ac_cv_lib_posix_remove" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" +fi + + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" +if test "x$ac_cv_func_shmat" = xyes; then : + +fi + + if test $ac_cv_func_shmat = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 +$as_echo_n "checking for shmat in -lipc... " >&6; } +if ${ac_cv_lib_ipc_shmat+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lipc $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shmat (); +int +main () +{ +return shmat (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ipc_shmat=yes +else + ac_cv_lib_ipc_shmat=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 +$as_echo "$ac_cv_lib_ipc_shmat" >&6; } +if test "x$ac_cv_lib_ipc_shmat" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" +fi + + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS=$LDFLAGS + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # John Interrante, Karl Berry + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 +$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } +if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char IceConnectionNumber (); +int +main () +{ +return IceConnectionNumber (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ICE_IceConnectionNumber=yes +else + ac_cv_lib_ICE_IceConnectionNumber=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 +$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } +if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then : + X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" +fi + + LDFLAGS=$ac_save_LDFLAGS + +fi + + + if test "$zOSUnix" = "yes"; then + CFLAGS="$CFLAGS -W c,dll" + LDFLAGS="$LDFLAGS -W l,dll" + X_EXTRA_LIBS="$X_EXTRA_LIBS -lSM -lICE -lXmu" + fi + + + if test -d "$x_includes" && test ! -d "$x_libraries"; then + x_libraries=`echo "$x_includes" | sed s/include/lib/` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Corrected X libraries to $x_libraries" >&5 +$as_echo "Corrected X libraries to $x_libraries" >&6; } + X_LIBS="$X_LIBS -L$x_libraries" + if test "$vim_cv_uname_output" = SunOS && + echo $vim_cv_uname_r_output | grep '^5' >/dev/null; then + X_LIBS="$X_LIBS -R $x_libraries" + fi + fi + + if test -d "$x_libraries" && test ! -d "$x_includes"; then + x_includes=`echo "$x_libraries" | sed s/lib/include/` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Corrected X includes to $x_includes" >&5 +$as_echo "Corrected X includes to $x_includes" >&6; } + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + X_CFLAGS="`echo $X_CFLAGS\ | sed 's%-I/usr/include %%'`" + X_LIBS="`echo $X_LIBS\ | sed 's%-L/usr/lib %%'`" + X_LIBS="`echo $X_LIBS\ | sed -e 's%-R/usr/lib %%' -e 's%-R /usr/lib %%'`" + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if X11 header files can be found" >&5 +$as_echo_n "checking if X11 header files can be found... " >&6; } + cflags_save=$CFLAGS + CFLAGS="$CFLAGS $X_CFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; no_x=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$cflags_save + + if test "${no_x-no}" = yes; then + with_x=no + else + $as_echo "#define HAVE_X11 1" >>confdefs.h + + X_LIB="-lXt -lX11"; + + + ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="-L$x_libraries $LDFLAGS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _XdmcpAuthDoIt in -lXdmcp" >&5 +$as_echo_n "checking for _XdmcpAuthDoIt in -lXdmcp... " >&6; } +if ${ac_cv_lib_Xdmcp__XdmcpAuthDoIt+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lXdmcp -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lXdmcp $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char _XdmcpAuthDoIt (); +int +main () +{ +return _XdmcpAuthDoIt (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_Xdmcp__XdmcpAuthDoIt=yes +else + ac_cv_lib_Xdmcp__XdmcpAuthDoIt=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xdmcp__XdmcpAuthDoIt" >&5 +$as_echo "$ac_cv_lib_Xdmcp__XdmcpAuthDoIt" >&6; } +if test "x$ac_cv_lib_Xdmcp__XdmcpAuthDoIt" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lXdmcp" +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceOpenConnection in -lICE" >&5 +$as_echo_n "checking for IceOpenConnection in -lICE... " >&6; } +if ${ac_cv_lib_ICE_IceOpenConnection+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char IceOpenConnection (); +int +main () +{ +return IceOpenConnection (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ICE_IceOpenConnection=yes +else + ac_cv_lib_ICE_IceOpenConnection=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceOpenConnection" >&5 +$as_echo "$ac_cv_lib_ICE_IceOpenConnection" >&6; } +if test "x$ac_cv_lib_ICE_IceOpenConnection" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lSM -lICE" +fi + + + LDFLAGS="$X_LIBS $ac_save_LDFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XpmCreatePixmapFromData in -lXpm" >&5 +$as_echo_n "checking for XpmCreatePixmapFromData in -lXpm... " >&6; } +if ${ac_cv_lib_Xpm_XpmCreatePixmapFromData+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lXpm -lXt $X_PRE_LIBS -lXpm -lX11 $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XpmCreatePixmapFromData (); +int +main () +{ +return XpmCreatePixmapFromData (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_Xpm_XpmCreatePixmapFromData=yes +else + ac_cv_lib_Xpm_XpmCreatePixmapFromData=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xpm_XpmCreatePixmapFromData" >&5 +$as_echo "$ac_cv_lib_Xpm_XpmCreatePixmapFromData" >&6; } +if test "x$ac_cv_lib_Xpm_XpmCreatePixmapFromData" = xyes; then : + X_PRE_LIBS="$X_PRE_LIBS -lXpm" +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if X11 header files implicitly declare return values" >&5 +$as_echo_n "checking if X11 header files implicitly declare return values... " >&6; } + cflags_save=$CFLAGS + if test "$GCC" = yes; then + CFLAGS="$CFLAGS $X_CFLAGS -Werror" + else + CFLAGS="$CFLAGS $X_CFLAGS" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +else + CFLAGS="$CFLAGS -Wno-implicit-int" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; cflags_save="$cflags_save -Wno-implicit-int" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: test failed" >&5 +$as_echo "test failed" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$cflags_save + + LDFLAGS="$ac_save_LDFLAGS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of wchar_t is 2 bytes" >&5 +$as_echo_n "checking size of wchar_t is 2 bytes... " >&6; } + if ${ac_cv_small_wchar_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + as_fn_error $? "failed to compile test program" "$LINENO" 5 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#if STDC_HEADERS +# include +# include +#endif + int main() + { + if (sizeof(wchar_t) <= 2) + exit(1); + exit(0); + } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_small_wchar_t="no" +else + ac_cv_small_wchar_t="yes" +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_small_wchar_t" >&5 +$as_echo "$ac_cv_small_wchar_t" >&6; } + if test "x$ac_cv_small_wchar_t" = "xyes" ; then + $as_echo "#define SMALL_WCHAR_T 1" >>confdefs.h + + fi + + fi +fi + +if test "x$with_x" = xno -a "x$with_x_arg" = xyes; then + as_fn_error $? "could not configure X" "$LINENO" 5 +fi + +test "x$with_x" = xno -a "x$HAIKU" != "xyes" -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && enable_gui=no + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-gui argument" >&5 +$as_echo_n "checking --enable-gui argument... " >&6; } +# Check whether --enable-gui was given. +if test "${enable_gui+set}" = set; then : + enableval=$enable_gui; +else + enable_gui="auto" +fi + + +enable_gui_canon=`echo "_$enable_gui" | \ + sed 's/[ _+-]//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` + +SKIP_GTK2=YES +SKIP_GTK3=YES +SKIP_GNOME=YES +SKIP_MOTIF=YES +SKIP_PHOTON=YES +SKIP_HAIKU=YES +GUITYPE=NONE + +if test "x$HAIKU" = "xyes"; then + SKIP_HAIKU= + case "$enable_gui_canon" in + no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI support" >&5 +$as_echo "no GUI support" >&6; } + SKIP_HAIKU=YES ;; + yes|"") { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes - automatic GUI support" >&5 +$as_echo "yes - automatic GUI support" >&6; } ;; + auto) { $as_echo "$as_me:${as_lineno-$LINENO}: result: auto - automatic GUI support" >&5 +$as_echo "auto - automatic GUI support" >&6; } ;; + haiku) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Haiku GUI support" >&5 +$as_echo "Haiku GUI support" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Sorry, $enable_gui GUI is not supported" >&5 +$as_echo "Sorry, $enable_gui GUI is not supported" >&6; } + SKIP_HAIKU=YES ;; + esac +elif test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then + SKIP_PHOTON= + case "$enable_gui_canon" in + no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI support" >&5 +$as_echo "no GUI support" >&6; } + SKIP_PHOTON=YES ;; + yes|""|auto) { $as_echo "$as_me:${as_lineno-$LINENO}: result: automatic GUI support" >&5 +$as_echo "automatic GUI support" >&6; } + gui_auto=yes ;; + photon) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Photon GUI support" >&5 +$as_echo "Photon GUI support" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Sorry, $enable_gui GUI is not supported" >&5 +$as_echo "Sorry, $enable_gui GUI is not supported" >&6; } + SKIP_PHOTON=YES ;; + esac + +elif test "x$MACOS_X" = "xyes" -a "x$with_x" = "xno" ; then + case "$enable_gui_canon" in + no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI support" >&5 +$as_echo "no GUI support" >&6; } ;; + yes|"") { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes - automatic GUI support" >&5 +$as_echo "yes - automatic GUI support" >&6; } + gui_auto=yes ;; + auto) { $as_echo "$as_me:${as_lineno-$LINENO}: result: auto - disable GUI support for Mac OS" >&5 +$as_echo "auto - disable GUI support for Mac OS" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Sorry, $enable_gui GUI is not supported" >&5 +$as_echo "Sorry, $enable_gui GUI is not supported" >&6; } ;; + esac +else + + case "$enable_gui_canon" in + no|none) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI support" >&5 +$as_echo "no GUI support" >&6; } ;; + yes|""|auto) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes/auto - automatic GUI support" >&5 +$as_echo "yes/auto - automatic GUI support" >&6; } + gui_auto=yes + SKIP_GTK2= + SKIP_GTK3= + SKIP_GNOME= + SKIP_MOTIF=;; + gtk2) { $as_echo "$as_me:${as_lineno-$LINENO}: result: GTK+ 2.x GUI support" >&5 +$as_echo "GTK+ 2.x GUI support" >&6; } + SKIP_GTK2=;; + gnome2) { $as_echo "$as_me:${as_lineno-$LINENO}: result: GNOME 2.x GUI support" >&5 +$as_echo "GNOME 2.x GUI support" >&6; } + SKIP_GNOME= + SKIP_GTK2=;; + gtk3) { $as_echo "$as_me:${as_lineno-$LINENO}: result: GTK+ 3.x GUI support" >&5 +$as_echo "GTK+ 3.x GUI support" >&6; } + SKIP_GTK3=;; + motif) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Motif GUI support" >&5 +$as_echo "Motif GUI support" >&6; } + SKIP_MOTIF=;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Sorry, $enable_gui GUI is not supported" >&5 +$as_echo "Sorry, $enable_gui GUI is not supported" >&6; } ;; + esac + +fi + +if test "x$SKIP_GTK2" != "xYES" -a "$enable_gui_canon" != "gtk2" \ + -a "$enable_gui_canon" != "gnome2"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for GTK+ 2" >&5 +$as_echo_n "checking whether or not to look for GTK+ 2... " >&6; } + # Check whether --enable-gtk2-check was given. +if test "${enable_gtk2_check+set}" = set; then : + enableval=$enable_gtk2_check; +else + enable_gtk2_check="yes" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gtk2_check" >&5 +$as_echo "$enable_gtk2_check" >&6; } + if test "x$enable_gtk2_check" = "xno"; then + SKIP_GTK2=YES + SKIP_GNOME=YES + fi +fi + +if test "x$SKIP_GNOME" != "xYES" -a "$enable_gui_canon" != "gnome2"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for GNOME" >&5 +$as_echo_n "checking whether or not to look for GNOME... " >&6; } + # Check whether --enable-gnome-check was given. +if test "${enable_gnome_check+set}" = set; then : + enableval=$enable_gnome_check; +else + enable_gnome_check="no" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gnome_check" >&5 +$as_echo "$enable_gnome_check" >&6; } + if test "x$enable_gnome_check" = "xno"; then + SKIP_GNOME=YES + fi +fi + +if test "x$SKIP_GTK3" != "xYES" -a "$enable_gui_canon" != "gtk3"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for GTK+ 3" >&5 +$as_echo_n "checking whether or not to look for GTK+ 3... " >&6; } + # Check whether --enable-gtk3-check was given. +if test "${enable_gtk3_check+set}" = set; then : + enableval=$enable_gtk3_check; +else + enable_gtk3_check="yes" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gtk3_check" >&5 +$as_echo "$enable_gtk3_check" >&6; } + if test "x$enable_gtk3_check" = "xno"; then + SKIP_GTK3=YES + fi +fi + +if test "x$SKIP_MOTIF" != "xYES" -a "$enable_gui_canon" != "motif"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for Motif" >&5 +$as_echo_n "checking whether or not to look for Motif... " >&6; } + # Check whether --enable-motif-check was given. +if test "${enable_motif_check+set}" = set; then : + enableval=$enable_motif_check; +else + enable_motif_check="yes" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_motif_check" >&5 +$as_echo "$enable_motif_check" >&6; } + if test "x$enable_motif_check" = "xno"; then + SKIP_MOTIF=YES + fi +fi + + + + + + + +if test "X$PKG_CONFIG" = "X"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +$as_echo "$ac_pt_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi + + +if test -z "$SKIP_GTK2"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-gtktest argument" >&5 +$as_echo_n "checking --disable-gtktest argument... " >&6; } + # Check whether --enable-gtktest was given. +if test "${enable_gtktest+set}" = set; then : + enableval=$enable_gtktest; +else + enable_gtktest=yes +fi + + if test "x$enable_gtktest" = "xyes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test enabled" >&5 +$as_echo "gtk test enabled" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test disabled" >&5 +$as_echo "gtk test disabled" >&6; } + fi + + if test "x$PKG_CONFIG" != "xno"; then + save_skip_gtk3=$SKIP_GTK3 + SKIP_GTK3=YES + + if test "X$GTK_CONFIG" != "Xno" -o "X$PKG_CONFIG" != "Xno"; then + { + no_gtk="" + if (test "X$SKIP_GTK2" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ + && $PKG_CONFIG --exists gtk+-2.0; then + { + min_gtk_version=2.2.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5 +$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; } + GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-2.0` + GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-2.0` + GTK_LIBS=`$PKG_CONFIG --libs gtk+-2.0` + gtk_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + gtk_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + gtk_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + } + elif (test "X$SKIP_GTK3" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ + && $PKG_CONFIG --exists gtk+-3.0; then + { + min_gtk_version=2.2.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5 +$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; } + + GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-3.0` + GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-3.0` + GTK_LIBS=`$PKG_CONFIG --libs gtk+-3.0` + gtk_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + gtk_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + gtk_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK -dev package" >&5 +$as_echo_n "checking for GTK -dev package... " >&6; } + no_gtk=yes + fi + + if test "x$enable_gtktest" = "xyes" -a "x$no_gtk" = "x"; then + { + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + + rm -f conf.gtktest + if test "$cross_compiling" = yes; then : + echo $ac_n "cross compiling; assumed OK... $ac_c" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#if STDC_HEADERS +# include +# include +#endif + +int +main () +{ +int major, minor, micro; +char *tmp_version; + +system ("touch conf.gtktest"); + +/* HP/UX 9 (%@#!) writes to sscanf strings */ +tmp_version = g_strdup("$min_gtk_version"); +if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_gtk_version"); + exit(1); + } + +if ((gtk_major_version > major) || + ((gtk_major_version == major) && (gtk_minor_version > minor)) || + ((gtk_major_version == major) && (gtk_minor_version == minor) && + (gtk_micro_version >= micro))) +{ + return 0; +} +return 1; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + no_gtk=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + } + fi + if test "x$no_gtk" = x ; then + if test "x$enable_gtktest" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5 +$as_echo "yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5 +$as_echo "found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; } + fi + GUI_LIB_LOC="$GTK_LIBDIR" + GTK_LIBNAME="$GTK_LIBS" + GUI_INC_LOC="$GTK_CFLAGS" + else + { + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + GTK_CFLAGS="" + GTK_LIBS="" + : + if test "$fail_if_missing" = "yes" -a "X$gui_auto" != "Xyes"; then + as_fn_error $? "could not configure GTK" "$LINENO" 5 + fi + } + fi + } + else + GTK_CFLAGS="" + GTK_LIBS="" + : + fi + + + rm -f conf.gtktest + + if test "x$GTK_CFLAGS" != "x"; then + SKIP_GTK3=YES + SKIP_MOTIF=YES + GUITYPE=GTK + + else + SKIP_GTK3=$save_skip_gtk3 + fi + fi + if test "x$GUITYPE" = "xGTK"; then + if test -z "$SKIP_GNOME"; then + { + + + + + + +# Check whether --with-gnome-includes was given. +if test "${with_gnome_includes+set}" = set; then : + withval=$with_gnome_includes; CFLAGS="$CFLAGS -I$withval" + +fi + + + +# Check whether --with-gnome-libs was given. +if test "${with_gnome_libs+set}" = set; then : + withval=$with_gnome_libs; LDFLAGS="$LDFLAGS -L$withval" gnome_prefix=$withval + +fi + + + +# Check whether --with-gnome was given. +if test "${with_gnome+set}" = set; then : + withval=$with_gnome; if test x$withval = xyes; then + want_gnome=yes + have_gnome=yes + else + if test "x$withval" = xno; then + want_gnome=no + else + want_gnome=yes + LDFLAGS="$LDFLAGS -L$withval/lib" + CFLAGS="$CFLAGS -I$withval/include" + gnome_prefix=$withval/lib + fi + fi +else + want_gnome=yes +fi + + + if test "x$want_gnome" = xyes; then + { + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libgnomeui-2.0" >&5 +$as_echo_n "checking for libgnomeui-2.0... " >&6; } + if $PKG_CONFIG --exists libgnomeui-2.0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + GNOME_LIBS=`$PKG_CONFIG --libs-only-l libgnomeui-2.0` + GNOME_LIBDIR=`$PKG_CONFIG --libs-only-L libgnomeui-2.0` + GNOME_INCLUDEDIR=`$PKG_CONFIG --cflags libgnomeui-2.0` + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FreeBSD" >&5 +$as_echo_n "checking for FreeBSD... " >&6; } + if test "$vim_cv_uname_output" = FreeBSD; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + GNOME_INCLUDEDIR="$GNOME_INCLUDEDIR -D_THREAD_SAFE" + GNOME_LIBS="$GNOME_LIBS -pthread" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + have_gnome=yes + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + if test "x" = xfail; then + as_fn_error $? "Could not find libgnomeui-2.0 via pkg-config" "$LINENO" 5 + fi + fi + } + fi + + if test "x$have_gnome" = xyes ; then + $as_echo "#define FEAT_GUI_GNOME 1" >>confdefs.h + + GUI_INC_LOC="$GUI_INC_LOC $GNOME_INCLUDEDIR" + GTK_LIBNAME="$GTK_LIBNAME $GNOME_LIBDIR $GNOME_LIBS" + fi + } + fi + fi +fi + + +if test -z "$SKIP_GTK3"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-gtktest argument" >&5 +$as_echo_n "checking --disable-gtktest argument... " >&6; } + # Check whether --enable-gtktest was given. +if test "${enable_gtktest+set}" = set; then : + enableval=$enable_gtktest; +else + enable_gtktest=yes +fi + + if test "x$enable_gtktest" = "xyes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test enabled" >&5 +$as_echo "gtk test enabled" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test disabled" >&5 +$as_echo "gtk test disabled" >&6; } + fi + + if test "x$PKG_CONFIG" != "xno"; then + save_skip_gtk2=$SKIP_GTK2 + SKIP_GTK2=YES + + if test "X$GTK_CONFIG" != "Xno" -o "X$PKG_CONFIG" != "Xno"; then + { + no_gtk="" + if (test "X$SKIP_GTK2" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ + && $PKG_CONFIG --exists gtk+-2.0; then + { + min_gtk_version=3.0.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5 +$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; } + GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-2.0` + GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-2.0` + GTK_LIBS=`$PKG_CONFIG --libs gtk+-2.0` + gtk_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + gtk_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + gtk_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + } + elif (test "X$SKIP_GTK3" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ + && $PKG_CONFIG --exists gtk+-3.0; then + { + min_gtk_version=3.0.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5 +$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; } + + GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-3.0` + GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-3.0` + GTK_LIBS=`$PKG_CONFIG --libs gtk+-3.0` + gtk_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + gtk_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + gtk_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK -dev package" >&5 +$as_echo_n "checking for GTK -dev package... " >&6; } + no_gtk=yes + fi + + if test "x$enable_gtktest" = "xyes" -a "x$no_gtk" = "x"; then + { + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + + rm -f conf.gtktest + if test "$cross_compiling" = yes; then : + echo $ac_n "cross compiling; assumed OK... $ac_c" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#if STDC_HEADERS +# include +# include +#endif + +int +main () +{ +int major, minor, micro; +char *tmp_version; + +system ("touch conf.gtktest"); + +/* HP/UX 9 (%@#!) writes to sscanf strings */ +tmp_version = g_strdup("$min_gtk_version"); +if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_gtk_version"); + exit(1); + } + +if ((gtk_major_version > major) || + ((gtk_major_version == major) && (gtk_minor_version > minor)) || + ((gtk_major_version == major) && (gtk_minor_version == minor) && + (gtk_micro_version >= micro))) +{ + return 0; +} +return 1; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + no_gtk=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + } + fi + if test "x$no_gtk" = x ; then + if test "x$enable_gtktest" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5 +$as_echo "yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5 +$as_echo "found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; } + fi + GUI_LIB_LOC="$GTK_LIBDIR" + GTK_LIBNAME="$GTK_LIBS" + GUI_INC_LOC="$GTK_CFLAGS" + else + { + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + GTK_CFLAGS="" + GTK_LIBS="" + : + if test "$fail_if_missing" = "yes" -a "X$gui_auto" != "Xyes"; then + as_fn_error $? "could not configure GTK" "$LINENO" 5 + fi + } + fi + } + else + GTK_CFLAGS="" + GTK_LIBS="" + : + fi + + + rm -f conf.gtktest + + if test "x$GTK_CFLAGS" != "x"; then + SKIP_GTK2=YES + SKIP_GNOME=YES + SKIP_MOTIF=YES + GUITYPE=GTK + + $as_echo "#define USE_GTK3 1" >>confdefs.h + + else + SKIP_GTK2=$save_skip_gtk2 + fi + fi +fi + +if test "x$GUITYPE" = "xGTK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of Gdk-Pixbuf" >&5 +$as_echo_n "checking version of Gdk-Pixbuf... " >&6; } + gdk_pixbuf_version=`$PKG_CONFIG --modversion gdk-pixbuf-2.0` + if test "x$gdk_pixbuf_version" != x ; then + gdk_pixbuf_version_minor=`echo $gdk_pixbuf_version | \ + sed -e 's/[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*/\1/'` + if test "x$gdk_pixbuf_version_minor" != x -a \ + $gdk_pixbuf_version_minor -ge 31 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK." >&5 +$as_echo "OK." >&6; } + # Extract the first word of "glib-compile-resources", so it can be a program name with args. +set dummy glib-compile-resources; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GLIB_COMPILE_RESOURCES+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GLIB_COMPILE_RESOURCES in + [\\/]* | ?:[\\/]*) + ac_cv_path_GLIB_COMPILE_RESOURCES="$GLIB_COMPILE_RESOURCES" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GLIB_COMPILE_RESOURCES="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_GLIB_COMPILE_RESOURCES" && ac_cv_path_GLIB_COMPILE_RESOURCES="no" + ;; +esac +fi +GLIB_COMPILE_RESOURCES=$ac_cv_path_GLIB_COMPILE_RESOURCES +if test -n "$GLIB_COMPILE_RESOURCES"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GLIB_COMPILE_RESOURCES" >&5 +$as_echo "$GLIB_COMPILE_RESOURCES" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking glib-compile-resources" >&5 +$as_echo_n "checking glib-compile-resources... " >&6; } + if test "x$GLIB_COMPILE_RESOURCES" = xno ; then + GLIB_COMPILE_RESOURCES="" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot be found in PATH." >&5 +$as_echo "cannot be found in PATH." >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: usable." >&5 +$as_echo "usable." >&6; } + $as_echo "#define USE_GRESOURCE 1" >>confdefs.h + + GRESOURCE_SRC="auto/gui_gtk_gresources.c" + GRESOURCE_OBJ="objects/gui_gtk_gresources.o" + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable." >&5 +$as_echo "not usable." >&6; } + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot obtain from pkg_config." >&5 +$as_echo "cannot obtain from pkg_config." >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-icon-cache-update argument" >&5 +$as_echo_n "checking --disable-icon-cache-update argument... " >&6; } + # Check whether --enable-icon_cache_update was given. +if test "${enable_icon_cache_update+set}" = set; then : + enableval=$enable_icon_cache_update; +else + enable_icon_cache_update="yes" +fi + + if test "$enable_icon_cache_update" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not set" >&5 +$as_echo "not set" >&6; } + # Extract the first word of "gtk-update-icon-cache", so it can be a program name with args. +set dummy gtk-update-icon-cache; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GTK_UPDATE_ICON_CACHE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GTK_UPDATE_ICON_CACHE in + [\\/]* | ?:[\\/]*) + ac_cv_path_GTK_UPDATE_ICON_CACHE="$GTK_UPDATE_ICON_CACHE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GTK_UPDATE_ICON_CACHE="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_GTK_UPDATE_ICON_CACHE" && ac_cv_path_GTK_UPDATE_ICON_CACHE="no" + ;; +esac +fi +GTK_UPDATE_ICON_CACHE=$ac_cv_path_GTK_UPDATE_ICON_CACHE +if test -n "$GTK_UPDATE_ICON_CACHE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GTK_UPDATE_ICON_CACHE" >&5 +$as_echo "$GTK_UPDATE_ICON_CACHE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$GTK_UPDATE_ICON_CACHE" = "xno" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found in PATH." >&5 +$as_echo "not found in PATH." >&6; } + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: update disabled" >&5 +$as_echo "update disabled" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-desktop-database-update argument" >&5 +$as_echo_n "checking --disable-desktop-database-update argument... " >&6; } + # Check whether --enable-desktop_database_update was given. +if test "${enable_desktop_database_update+set}" = set; then : + enableval=$enable_desktop_database_update; +else + enable_desktop_database_update="yes" +fi + + if test "$enable_desktop_database_update" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not set" >&5 +$as_echo "not set" >&6; } + # Extract the first word of "update-desktop-database", so it can be a program name with args. +set dummy update-desktop-database; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_UPDATE_DESKTOP_DATABASE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $UPDATE_DESKTOP_DATABASE in + [\\/]* | ?:[\\/]*) + ac_cv_path_UPDATE_DESKTOP_DATABASE="$UPDATE_DESKTOP_DATABASE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_UPDATE_DESKTOP_DATABASE="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_UPDATE_DESKTOP_DATABASE" && ac_cv_path_UPDATE_DESKTOP_DATABASE="no" + ;; +esac +fi +UPDATE_DESKTOP_DATABASE=$ac_cv_path_UPDATE_DESKTOP_DATABASE +if test -n "$UPDATE_DESKTOP_DATABASE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UPDATE_DESKTOP_DATABASE" >&5 +$as_echo "$UPDATE_DESKTOP_DATABASE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$UPDATE_DESKTOP_DATABASE" = "xno" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found in PATH." >&5 +$as_echo "not found in PATH." >&6; } + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: update disabled" >&5 +$as_echo "update disabled" >&6; } + fi +fi + + + + + + + +if test -z "$SKIP_MOTIF"; then + gui_XXX="/usr/XXX/Motif* /usr/Motif*/XXX /usr/XXX /usr/shlib /usr/X11*/XXX /usr/XXX/X11* /usr/dt/XXX /local/Motif*/XXX /local/XXX/Motif* /usr/local/Motif*/XXX /usr/local/XXX/Motif* /usr/local/XXX /usr/local/X11*/XXX /usr/local/LessTif/Motif*/XXX $MOTIFHOME/XXX" + GUI_INC_LOC="`echo $GUI_INC_LOC|sed 's%-I%%g'`" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of Motif GUI includes" >&5 +$as_echo_n "checking for location of Motif GUI includes... " >&6; } + gui_includes="`echo $x_includes|sed 's%/^/^/*$%%'` `echo "$gui_XXX" | sed s/XXX/include/g` $GUI_INC_LOC" + GUI_INC_LOC= + for try in $gui_includes; do + if test -f "$try/Xm/Xm.h"; then + GUI_INC_LOC=$try + fi + done + if test -n "$GUI_INC_LOC"; then + if test "$GUI_INC_LOC" = /usr/include; then + GUI_INC_LOC= + { $as_echo "$as_me:${as_lineno-$LINENO}: result: in default path" >&5 +$as_echo "in default path" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GUI_INC_LOC" >&5 +$as_echo "$GUI_INC_LOC" >&6; } + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 +$as_echo "" >&6; } + SKIP_MOTIF=YES + fi +fi + + +if test -z "$SKIP_MOTIF"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-motif-lib argument" >&5 +$as_echo_n "checking --with-motif-lib argument... " >&6; } + +# Check whether --with-motif-lib was given. +if test "${with_motif_lib+set}" = set; then : + withval=$with_motif_lib; MOTIF_LIBNAME="${withval}" +fi + + + if test -n "$MOTIF_LIBNAME"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MOTIF_LIBNAME" >&5 +$as_echo "$MOTIF_LIBNAME" >&6; } + GUI_LIB_LOC= + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + GUI_LIB_LOC="`echo $GUI_LIB_LOC|sed 's%-L%%g'`" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of Motif GUI libs" >&5 +$as_echo_n "checking for location of Motif GUI libs... " >&6; } + gui_libs="`echo $x_libraries|sed 's%/^/^/*$%%'` `echo "$gui_XXX" | sed s/XXX/lib/g` /usr/lib/i386-linux-gnu /usr/lib/x86_64-linux-gnu `echo "$GUI_INC_LOC" | sed s/include/lib/` $GUI_LIB_LOC" + GUI_LIB_LOC= + for try in $gui_libs; do + for libtry in "$try"/libXm.a "$try"/libXm.dll.a "$try"/libXm.so* "$try"/libXm.sl "$try"/libXm.dylib; do + if test -f "$libtry"; then + GUI_LIB_LOC=$try + fi + done + done + if test -n "$GUI_LIB_LOC"; then + if test "$GUI_LIB_LOC" = /usr/lib \ + -o "$GUI_LIB_LOC" = /usr/lib/i386-linux-gnu \ + -o "$GUI_LIB_LOC" = /usr/lib/x86_64-linux-gnu; then + GUI_LIB_LOC= + { $as_echo "$as_me:${as_lineno-$LINENO}: result: in default path" >&5 +$as_echo "in default path" >&6; } + else + if test -n "$GUI_LIB_LOC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GUI_LIB_LOC" >&5 +$as_echo "$GUI_LIB_LOC" >&6; } + if test "$vim_cv_uname_output" = SunOS && + echo $vim_cv_uname_r_output | grep '^5' >/dev/null; then + GUI_LIB_LOC="$GUI_LIB_LOC -R $GUI_LIB_LOC" + fi + fi + fi + MOTIF_LIBNAME=-lXm + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 +$as_echo "" >&6; } + SKIP_MOTIF=YES + fi + fi +fi + +if test -z "$SKIP_MOTIF"; then + GUITYPE=MOTIF + +fi + +if test -z "$SKIP_MOTIF"; then + if test -n "$GUI_INC_LOC"; then + GUI_INC_LOC=-I"`echo $GUI_INC_LOC|sed 's%-I%%'`" + fi + if test -n "$GUI_LIB_LOC"; then + GUI_LIB_LOC=-L"`echo $GUI_LIB_LOC|sed 's%-L%%'`" + fi + + ldflags_save=$LDFLAGS + LDFLAGS="$X_LIBS $LDFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XShapeQueryExtension in -lXext" >&5 +$as_echo_n "checking for XShapeQueryExtension in -lXext... " >&6; } +if ${ac_cv_lib_Xext_XShapeQueryExtension+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lXext -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XShapeQueryExtension (); +int +main () +{ +return XShapeQueryExtension (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_Xext_XShapeQueryExtension=yes +else + ac_cv_lib_Xext_XShapeQueryExtension=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xext_XShapeQueryExtension" >&5 +$as_echo "$ac_cv_lib_Xext_XShapeQueryExtension" >&6; } +if test "x$ac_cv_lib_Xext_XShapeQueryExtension" = xyes; then : + GUI_X_LIBS="-lXext" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wslen in -lw" >&5 +$as_echo_n "checking for wslen in -lw... " >&6; } +if ${ac_cv_lib_w_wslen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lw $GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char wslen (); +int +main () +{ +return wslen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_w_wslen=yes +else + ac_cv_lib_w_wslen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_w_wslen" >&5 +$as_echo "$ac_cv_lib_w_wslen" >&6; } +if test "x$ac_cv_lib_w_wslen" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lw" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym in -ldl" >&5 +$as_echo_n "checking for dlsym in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlsym+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlsym (); +int +main () +{ +return dlsym (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlsym=yes +else + ac_cv_lib_dl_dlsym=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlsym" >&5 +$as_echo "$ac_cv_lib_dl_dlsym" >&6; } +if test "x$ac_cv_lib_dl_dlsym" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldl" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XmuCreateStippledPixmap in -lXmu" >&5 +$as_echo_n "checking for XmuCreateStippledPixmap in -lXmu... " >&6; } +if ${ac_cv_lib_Xmu_XmuCreateStippledPixmap+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lXmu $GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XmuCreateStippledPixmap (); +int +main () +{ +return XmuCreateStippledPixmap (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_Xmu_XmuCreateStippledPixmap=yes +else + ac_cv_lib_Xmu_XmuCreateStippledPixmap=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xmu_XmuCreateStippledPixmap" >&5 +$as_echo "$ac_cv_lib_Xmu_XmuCreateStippledPixmap" >&6; } +if test "x$ac_cv_lib_Xmu_XmuCreateStippledPixmap" = xyes; then : + GUI_X_LIBS="-lXmu $GUI_X_LIBS" +fi + + if test -z "$SKIP_MOTIF"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XpEndJob in -lXp" >&5 +$as_echo_n "checking for XpEndJob in -lXp... " >&6; } +if ${ac_cv_lib_Xp_XpEndJob+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lXp $GUI_X_LIBS -lXm -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XpEndJob (); +int +main () +{ +return XpEndJob (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_Xp_XpEndJob=yes +else + ac_cv_lib_Xp_XpEndJob=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xp_XpEndJob" >&5 +$as_echo "$ac_cv_lib_Xp_XpEndJob" >&6; } +if test "x$ac_cv_lib_Xp_XpEndJob" = xyes; then : + GUI_X_LIBS="-lXp $GUI_X_LIBS" +fi + + fi + LDFLAGS=$ldflags_save + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for extra X11 defines" >&5 +$as_echo_n "checking for extra X11 defines... " >&6; } + NARROW_PROTO= + rm -fr conftestdir + if mkdir conftestdir; then + cd conftestdir + cat > Imakefile <<'EOF' +acfindx: + @echo 'NARROW_PROTO="${PROTO_DEFINES}"' +EOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + fi + cd .. + rm -fr conftestdir + fi + if test -z "$NARROW_PROTO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NARROW_PROTO" >&5 +$as_echo "$NARROW_PROTO" >&6; } + fi + +fi + +if test "$enable_xsmp" = "yes"; then + cppflags_save=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + for ac_header in X11/SM/SMlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "X11/SM/SMlib.h" "ac_cv_header_X11_SM_SMlib_h" "$ac_includes_default" +if test "x$ac_cv_header_X11_SM_SMlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_X11_SM_SMLIB_H 1 +_ACEOF + +fi + +done + + CPPFLAGS=$cppflags_save +fi + + +if test -z "$SKIP_MOTIF" -o -z "$SKIP_GTK2" -o -z "$SKIP_GTK3"; then + cppflags_save=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + for ac_header in X11/xpm.h X11/Sunkeysym.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + if test ! "$enable_xim" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XIMText in X11/Xlib.h" >&5 +$as_echo_n "checking for XIMText in X11/Xlib.h... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "XIMText" >/dev/null 2>&1; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no; xim has been disabled" >&5 +$as_echo "no; xim has been disabled" >&6; }; enable_xim="no" +fi +rm -f conftest* + + fi + CPPFLAGS=$cppflags_save + + if test "$enable_xim" = "auto" -a "x$GUITYPE" != "xNONE" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: X GUI selected; xim has been enabled" >&5 +$as_echo "X GUI selected; xim has been enabled" >&6; } + enable_xim="yes" + fi +fi + +if test -z "$SKIP_MOTIF"; then + cppflags_save=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11/Xmu/Editres.h" >&5 +$as_echo_n "checking for X11/Xmu/Editres.h... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +int +main () +{ +int i; i = 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define HAVE_X11_XMU_EDITRES_H 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CPPFLAGS=$cppflags_save +fi + +if test -z "$SKIP_MOTIF"; then + cppflags_save=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + if test "$zOSUnix" = "yes"; then + for ac_header in Xm/Xm.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "Xm/Xm.h" "ac_cv_header_Xm_Xm_h" "$ac_includes_default" +if test "x$ac_cv_header_Xm_Xm_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_XM_XM_H 1 +_ACEOF + +fi + +done + + else + for ac_header in Xm/Xm.h Xm/XpmP.h Xm/JoinSideT.h Xm/TraitP.h Xm/Manager.h Xm/UnhighlightT.h Xm/Notebook.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + fi + + if test "x$ac_cv_header_Xm_XpmP_h" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XpmAttributes_21 in Xm/XpmP.h" >&5 +$as_echo_n "checking for XpmAttributes_21 in Xm/XpmP.h... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +XpmAttributes_21 attr; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define XPMATTRIBUTES_TYPE XpmAttributes_21" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; $as_echo "#define XPMATTRIBUTES_TYPE XpmAttributes" >>confdefs.h + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + else + $as_echo "#define XPMATTRIBUTES_TYPE XpmAttributes" >>confdefs.h + + fi + CPPFLAGS=$cppflags_save +fi + +if test "x$GUITYPE" = "xNONE" -a "$enable_xim" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI selected; xim has been disabled" >&5 +$as_echo "no GUI selected; xim has been disabled" >&6; } + enable_xim="no" +fi +if test "x$GUITYPE" = "xNONE" -a "$enable_fontset" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI selected; fontset has been disabled" >&5 +$as_echo "no GUI selected; fontset has been disabled" >&6; } + enable_fontset="no" +fi +if test "x$GUITYPE:$enable_fontset" = "xGTK:yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: GTK+ 2 GUI selected; fontset has been disabled" >&5 +$as_echo "GTK+ 2 GUI selected; fontset has been disabled" >&6; } + enable_fontset="no" +fi + +if test -z "$SKIP_HAIKU"; then + GUITYPE=HAIKUGUI +fi + +if test -z "$SKIP_PHOTON"; then + GUITYPE=PHOTONGUI +fi + + + + + + +if test "$enable_workshop" = "yes" -a -n "$SKIP_MOTIF"; then + as_fn_error $? "cannot use workshop without Motif" "$LINENO" 5 +fi + +if test "$enable_xim" = "yes"; then + $as_echo "#define FEAT_XIM 1" >>confdefs.h + +fi +if test "$enable_fontset" = "yes"; then + $as_echo "#define FEAT_XFONTSET 1" >>confdefs.h + +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /proc link to executable" >&5 +$as_echo_n "checking for /proc link to executable... " >&6; } +if test -L "/proc/self/exe"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: /proc/self/exe" >&5 +$as_echo "/proc/self/exe" >&6; } + $as_echo "#define PROC_EXE_LINK \"/proc/self/exe\"" >>confdefs.h + +elif test -L "/proc/self/path/a.out"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: /proc/self/path/a.out" >&5 +$as_echo "/proc/self/path/a.out" >&6; } + $as_echo "#define PROC_EXE_LINK \"/proc/self/path/a.out\"" >>confdefs.h + +elif test -L "/proc/curproc/file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: /proc/curproc/file" >&5 +$as_echo "/proc/curproc/file" >&6; } + $as_echo "#define PROC_EXE_LINK \"/proc/curproc/file\"" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CYGWIN or MSYS environment" >&5 +$as_echo_n "checking for CYGWIN or MSYS environment... " >&6; } +case $vim_cv_uname_output in + CYGWIN*|MSYS*) CYGWIN=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CYGWIN clipboard support" >&5 +$as_echo_n "checking for CYGWIN clipboard support... " >&6; } + if test "x$with_x" = "xno" ; then + OS_EXTRA_SRC=winclip.c; OS_EXTRA_OBJ=objects/winclip.o + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define FEAT_CYGWIN_WIN32_CLIPBOARD 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no - using X11" >&5 +$as_echo "no - using X11" >&6; } + fi ;; + + *) CYGWIN=no; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; };; +esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether toupper is broken" >&5 +$as_echo_n "checking whether toupper is broken... " >&6; } +if ${vim_cv_toupper_broken+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + + as_fn_error $? "cross-compiling: please set 'vim_cv_toupper_broken'" "$LINENO" 5 + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include "confdefs.h" +#include +#if STDC_HEADERS +# include +# include +#endif +int main() { exit(toupper('A') == 'A' && tolower('z') == 'z'); } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + + vim_cv_toupper_broken=yes + +else + + vim_cv_toupper_broken=no + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_toupper_broken" >&5 +$as_echo "$vim_cv_toupper_broken" >&6; } + +if test "x$vim_cv_toupper_broken" = "xyes" ; then + $as_echo "#define BROKEN_TOUPPER 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __DATE__ and __TIME__ work" >&5 +$as_echo_n "checking whether __DATE__ and __TIME__ work... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +printf("(" __DATE__ " " __TIME__ ")"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_DATE_TIME 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __attribute__((unused)) is allowed" >&5 +$as_echo_n "checking whether __attribute__((unused)) is allowed... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int x __attribute__((unused)); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_ATTRIBUTE_UNUSED 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +ac_fn_c_check_header_mongrel "$LINENO" "elf.h" "ac_cv_header_elf_h" "$ac_includes_default" +if test "x$ac_cv_header_elf_h" = xyes; then : + HAS_ELF=1 +fi + + +if test "$HAS_ELF" = 1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lelf" >&5 +$as_echo_n "checking for main in -lelf... " >&6; } +if ${ac_cv_lib_elf_main+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lelf $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_elf_main=yes +else + ac_cv_lib_elf_main=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_elf_main" >&5 +$as_echo "$ac_cv_lib_elf_main" >&6; } +if test "x$ac_cv_lib_elf_main" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBELF 1 +_ACEOF + + LIBS="-lelf $LIBS" + +fi + +fi + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 +$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } +if eval \${$as_ac_Header+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include <$ac_hdr> + +int +main () +{ +if ((DIR *) 0) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$as_ac_Header=yes" +else + eval "$as_ac_Header=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$as_ac_Header + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 +_ACEOF + +ac_header_dirent=$ac_hdr; break +fi + +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 +$as_echo_n "checking for library containing opendir... " >&6; } +if ${ac_cv_search_opendir+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char opendir (); +int +main () +{ +return opendir (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dir; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_opendir=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_opendir+:} false; then : + break +fi +done +if ${ac_cv_search_opendir+:} false; then : + +else + ac_cv_search_opendir=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 +$as_echo "$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 +$as_echo_n "checking for library containing opendir... " >&6; } +if ${ac_cv_search_opendir+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char opendir (); +int +main () +{ +return opendir (); + ; + return 0; +} +_ACEOF +for ac_lib in '' x; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_opendir=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_opendir+:} false; then : + break +fi +done +if ${ac_cv_search_opendir+:} false; then : + +else + ac_cv_search_opendir=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 +$as_echo "$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +fi + + +if test $ac_cv_header_sys_wait_h = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that defines union wait" >&5 +$as_echo_n "checking for sys/wait.h that defines union wait... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +union wait xx, yy; xx = yy + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h + + $as_echo "#define HAVE_UNION_WAIT 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +for ac_header in stdint.h stdlib.h string.h \ + sys/select.h sys/utsname.h termcap.h fcntl.h \ + sgtty.h sys/ioctl.h sys/time.h sys/types.h \ + termio.h iconv.h inttypes.h langinfo.h math.h \ + unistd.h stropts.h errno.h sys/resource.h \ + sys/systeminfo.h locale.h sys/stream.h termios.h \ + libc.h sys/statfs.h poll.h sys/poll.h pwd.h \ + utime.h sys/param.h sys/ptms.h libintl.h libgen.h \ + util/debug.h util/msg18n.h frame.h sys/acl.h \ + sys/access.h sys/sysinfo.h wchar.h wctype.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in sys/ptem.h +do : + ac_fn_c_check_header_compile "$LINENO" "sys/ptem.h" "ac_cv_header_sys_ptem_h" "#if defined HAVE_SYS_STREAM_H +# include +#endif +" +if test "x$ac_cv_header_sys_ptem_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_PTEM_H 1 +_ACEOF + +fi + +done + + +for ac_header in sys/sysctl.h +do : + ac_fn_c_check_header_compile "$LINENO" "sys/sysctl.h" "ac_cv_header_sys_sysctl_h" "#if defined HAVE_SYS_PARAM_H +# include +#endif +" +if test "x$ac_cv_header_sys_sysctl_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_SYSCTL_H 1 +_ACEOF + +fi + +done + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_np.h" >&5 +$as_echo_n "checking for pthread_np.h... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +int +main () +{ +int i; i = 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define HAVE_PTHREAD_NP_H 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +for ac_header in strings.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default" +if test "x$ac_cv_header_strings_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRINGS_H 1 +_ACEOF + +fi + +done + +if test "x$MACOS_X" = "xyes"; then + $as_echo "#define NO_STRINGS_WITH_STRING_H 1" >>confdefs.h + +else + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if strings.h can be included after string.h" >&5 +$as_echo_n "checking if strings.h can be included after string.h... " >&6; } +cppflags_save=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $X_CFLAGS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if defined(_AIX) && !defined(_AIX51) && !defined(_NO_PROTO) +# define _NO_PROTO /* like in os_unix.h, causes conflict for AIX (Winn) */ + /* but don't do it on AIX 5.1 (Uribarri) */ +#endif +#ifdef HAVE_XM_XM_H +# include /* This breaks it for HP-UX 11 (Squassabia) */ +#endif +#ifdef HAVE_STRING_H +# include +#endif +#if defined(HAVE_STRINGS_H) +# include +#endif + +int +main () +{ +int i; i = 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + $as_echo "#define NO_STRINGS_WITH_STRING_H 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CPPFLAGS=$cppflags_save +fi + +if test $ac_cv_c_compiler_gnu = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 +$as_echo_n "checking whether $CC needs -traditional... " >&6; } +if ${ac_cv_prog_gcc_traditional+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_pattern="Autoconf.*'x'" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +Autoconf TIOCGETP +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +else + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +Autoconf TCGETA +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 +$as_echo "$ac_cv_prog_gcc_traditional" >&6; } + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +$as_echo_n "checking for an ANSI C-conforming const... " >&6; } +if ${ac_cv_c_const+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + +#ifndef __cplusplus + /* Ultrix mips cc rejects this sort of thing. */ + typedef int charset[2]; + const charset cs = { 0, 0 }; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this sort of thing. */ + char tx; + char *t = &tx; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; } bx; + struct s *b = &bx; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_const=yes +else + ac_cv_c_const=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +$as_echo "$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +$as_echo "#define const /**/" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5 +$as_echo_n "checking for working volatile... " >&6; } +if ${ac_cv_c_volatile+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + +volatile int x; +int * volatile y = (int *) 0; +return !x && !y; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_volatile=yes +else + ac_cv_c_volatile=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_volatile" >&5 +$as_echo "$ac_cv_c_volatile" >&6; } +if test $ac_cv_c_volatile = no; then + +$as_echo "#define volatile /**/" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" +if test "x$ac_cv_type_mode_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define mode_t int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" +if test "x$ac_cv_type_off_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define off_t long int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" +if test "x$ac_cv_type_pid_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 +$as_echo_n "checking for uid_t in sys/types.h... " >&6; } +if ${ac_cv_type_uid_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "uid_t" >/dev/null 2>&1; then : + ac_cv_type_uid_t=yes +else + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 +$as_echo "$ac_cv_type_uid_t" >&6; } +if test $ac_cv_type_uid_t = no; then + +$as_echo "#define uid_t int" >>confdefs.h + + +$as_echo "#define gid_t int" >>confdefs.h + +fi + +ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" +case $ac_cv_c_uint32_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT32_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint32_t $ac_cv_c_uint32_t +_ACEOF +;; + esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 +$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } +if ${ac_cv_header_time+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_time=yes +else + ac_cv_header_time=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 +$as_echo "$ac_cv_header_time" >&6; } +if test $ac_cv_header_time = yes; then + +$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "ino_t" "ac_cv_type_ino_t" "$ac_includes_default" +if test "x$ac_cv_type_ino_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define ino_t long +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "dev_t" "ac_cv_type_dev_t" "$ac_includes_default" +if test "x$ac_cv_type_dev_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define dev_t unsigned +_ACEOF + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if ${ac_cv_c_bigendian+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +;; #( + no) + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if ${ac_cv_c_inline+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rlim_t" >&5 +$as_echo_n "checking for rlim_t... " >&6; } +if eval "test \"`echo '$''{'ac_cv_type_rlim_t'+set}'`\" = set"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: (cached) $ac_cv_type_rlim_t" >&5 +$as_echo "(cached) $ac_cv_type_rlim_t" >&6; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#if STDC_HEADERS +# include +# include +#endif +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "(^|[^a-zA-Z_0-9])rlim_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : + ac_cv_type_rlim_t=yes +else + ac_cv_type_rlim_t=no +fi +rm -f conftest* + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_rlim_t" >&5 +$as_echo "$ac_cv_type_rlim_t" >&6; } +fi +if test $ac_cv_type_rlim_t = no; then + cat >> confdefs.h <<\EOF +#define rlim_t unsigned long +EOF +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stack_t" >&5 +$as_echo_n "checking for stack_t... " >&6; } +if eval "test \"`echo '$''{'ac_cv_type_stack_t'+set}'`\" = set"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: (cached) $ac_cv_type_stack_t" >&5 +$as_echo "(cached) $ac_cv_type_stack_t" >&6; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#if STDC_HEADERS +# include +# include +#endif +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "stack_t" >/dev/null 2>&1; then : + ac_cv_type_stack_t=yes +else + ac_cv_type_stack_t=no +fi +rm -f conftest* + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_stack_t" >&5 +$as_echo "$ac_cv_type_stack_t" >&6; } +fi +if test $ac_cv_type_stack_t = no; then + cat >> confdefs.h <<\EOF +#define stack_t struct sigaltstack +EOF +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stack_t has an ss_base field" >&5 +$as_echo_n "checking whether stack_t has an ss_base field... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#if STDC_HEADERS +# include +# include +#endif +#include +#include "confdefs.h" + +int +main () +{ +stack_t sigstk; sigstk.ss_base = 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_SS_BASE 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +olibs="$LIBS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-tlib argument" >&5 +$as_echo_n "checking --with-tlib argument... " >&6; } + +# Check whether --with-tlib was given. +if test "${with_tlib+set}" = set; then : + withval=$with_tlib; +fi + +if test -n "$with_tlib"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_tlib" >&5 +$as_echo "$with_tlib" >&6; } + LIBS="$LIBS -l$with_tlib" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for linking with $with_tlib library" >&5 +$as_echo_n "checking for linking with $with_tlib library... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK" >&5 +$as_echo "OK" >&6; } +else + as_fn_error $? "FAILED" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + olibs="$LIBS" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: empty: automatic terminal library selection" >&5 +$as_echo "empty: automatic terminal library selection" >&6; } + case "$vim_cv_uname_output" in + OSF1|SCO_SV) tlibs="tinfo ncurses curses termlib termcap";; + *) tlibs="tinfo ncurses termlib termcap curses";; + esac + for libname in $tlibs; do + as_ac_Lib=`$as_echo "ac_cv_lib_${libname}''_tgetent" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -l${libname}" >&5 +$as_echo_n "checking for tgetent in -l${libname}... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-l${libname} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char tgetent (); +int +main () +{ +return tgetent (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_LIB${libname}" | $as_tr_cpp` 1 +_ACEOF + + LIBS="-l${libname} $LIBS" + +fi + + if test "x$olibs" != "x$LIBS"; then + if test "$cross_compiling" = yes; then : + res="FAIL" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_TERMCAP_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif +int main() {char *s; s=(char *)tgoto("%p1%d", 0, 1); exit(0); } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + res="OK" +else + res="FAIL" +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + if test "$res" = "OK"; then + break + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libname library is not usable" >&5 +$as_echo "$libname library is not usable" >&6; } + LIBS="$olibs" + fi + done + if test "x$olibs" = "x$LIBS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no terminal library found" >&5 +$as_echo "no terminal library found" >&6; } + fi +fi + +if test "x$olibs" = "x$LIBS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent()" >&5 +$as_echo_n "checking for tgetent()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int tgetent(char *, const char *); +int +main () +{ +char s[10000]; int res = tgetent(s, "thisterminaldoesnotexist"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + as_fn_error $? "NOT FOUND! + You need to install a terminal library; for example ncurses. + On Linux that would be the libncurses-dev package. + Or specify the name of the library with --with-tlib." "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we talk terminfo" >&5 +$as_echo_n "checking whether we talk terminfo... " >&6; } +if ${vim_cv_terminfo+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + + as_fn_error $? "cross-compiling: please set 'vim_cv_terminfo'" "$LINENO" 5 + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include "confdefs.h" +#ifdef HAVE_TERMCAP_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif +int main() +{char *s; s=(char *)tgoto("%p1%d", 0, 1); exit(!strcmp(s==0 ? "" : s, "1")); } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + + vim_cv_terminfo=no + +else + + vim_cv_terminfo=yes + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_terminfo" >&5 +$as_echo "$vim_cv_terminfo" >&6; } + +if test "x$vim_cv_terminfo" = "xyes" ; then + $as_echo "#define TERMINFO 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking what tgetent() returns for an unknown terminal" >&5 +$as_echo_n "checking what tgetent() returns for an unknown terminal... " >&6; } +if ${vim_cv_tgetent+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + + as_fn_error $? "failed to compile test program." "$LINENO" 5 + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include "confdefs.h" +#ifdef HAVE_TERMCAP_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif +int main() +{char s[10000]; int res = tgetent(s, "thisterminaldoesnotexist"); exit(res != 0); } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + + vim_cv_tgetent=zero + +else + + vim_cv_tgetent=non-zero + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_tgetent" >&5 +$as_echo "$vim_cv_tgetent" >&6; } + +if test "x$vim_cv_tgetent" = "xzero" ; then + $as_echo "#define TGETENT_ZERO_ERR 0" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether termcap.h contains ospeed" >&5 +$as_echo_n "checking whether termcap.h contains ospeed... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_TERMCAP_H +# include +#endif + +int +main () +{ +ospeed = 20000 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_OSPEED 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ospeed can be extern" >&5 +$as_echo_n "checking whether ospeed can be extern... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_TERMCAP_H +# include +#endif +extern short ospeed; + +int +main () +{ +ospeed = 20000 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define OSPEED_EXTERN 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether termcap.h contains UP, BC and PC" >&5 +$as_echo_n "checking whether termcap.h contains UP, BC and PC... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_TERMCAP_H +# include +#endif + +int +main () +{ +if (UP == 0 && BC == 0) PC = 1 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_UP_BC_PC 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UP, BC and PC can be extern" >&5 +$as_echo_n "checking whether UP, BC and PC can be extern... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_TERMCAP_H +# include +#endif +extern char *UP, *BC, PC; + +int +main () +{ +if (UP == 0 && BC == 0) PC = 1 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define UP_BC_PC_EXTERN 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tputs() uses outfuntype" >&5 +$as_echo_n "checking whether tputs() uses outfuntype... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_TERMCAP_H +# include +#endif + +int +main () +{ +extern int xx(); tputs("test", 1, (outfuntype)xx) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_OUTFUNTYPE 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether del_curterm() can be used" >&5 +$as_echo_n "checking whether del_curterm() can be used... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_TERMCAP_H +# include +#endif +#include + +int +main () +{ +if (cur_term) del_curterm(cur_term); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_DEL_CURTERM 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/select.h and sys/time.h may both be included" >&5 +$as_echo_n "checking whether sys/select.h and sys/time.h may both be included... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define SYS_SELECT_WITH_SYS_TIME 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5 +$as_echo_n "checking for /dev/ptc... " >&6; } +if test -r /dev/ptc; then + $as_echo "#define HAVE_DEV_PTC 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SVR4 ptys" >&5 +$as_echo_n "checking for SVR4 ptys... " >&6; } +if test -c /dev/ptmx ; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +// These should be in stdlib.h, but it depends on _XOPEN_SOURCE. +char *ptsname(int); +int unlockpt(int); +int grantpt(int); + +int +main () +{ + + ptsname(0); + grantpt(0); + unlockpt(0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_SVR4_PTYS 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ptyranges" >&5 +$as_echo_n "checking for ptyranges... " >&6; } +if test -d /dev/ptym ; then + pdir='/dev/ptym' +else + pdir='/dev' +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef M_UNIX + yes; +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "yes" >/dev/null 2>&1; then : + ptys=`echo /dev/ptyp??` +else + ptys=`echo $pdir/pty??` +fi +rm -f conftest* + +if test "$ptys" != "$pdir/pty??" ; then + p0=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\).$/\1/g' | sort -u | tr -d '\012'` + p1=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\)$/\1/g' | sort -u | tr -d '\012'` + cat >>confdefs.h <<_ACEOF +#define PTYRANGE0 "$p0" +_ACEOF + + cat >>confdefs.h <<_ACEOF +#define PTYRANGE1 "$p1" +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p0 / $p1" >&5 +$as_echo "$p0 / $p1" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: don't know" >&5 +$as_echo "don't know" >&6; } +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sigcontext" >&5 +$as_echo_n "checking for struct sigcontext... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +int test_sig() +{ + struct sigcontext *scont; + scont = (struct sigcontext *)0; + return 1; +} +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define HAVE_SIGCONTEXT 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking getcwd implementation is broken" >&5 +$as_echo_n "checking getcwd implementation is broken... " >&6; } +if ${vim_cv_getcwd_broken+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + + as_fn_error $? "cross-compiling: please set 'vim_cv_getcwd_broken'" "$LINENO" 5 + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include "confdefs.h" +#ifdef HAVE_UNISTD_H +#include +#endif +char *dagger[] = { "IFS=pwd", 0 }; +int main() +{ + char buffer[500]; + extern char **environ; + environ = dagger; + return getcwd(buffer, 500) ? 0 : 1; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + + vim_cv_getcwd_broken=no + +else + + vim_cv_getcwd_broken=yes + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_getcwd_broken" >&5 +$as_echo "$vim_cv_getcwd_broken" >&6; } + +if test "x$vim_cv_getcwd_broken" = "xyes" ; then + $as_echo "#define BAD_GETCWD 1" >>confdefs.h + + for ac_func in getwd +do : + ac_fn_c_check_func "$LINENO" "getwd" "ac_cv_func_getwd" +if test "x$ac_cv_func_getwd" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETWD 1 +_ACEOF + +fi +done + +fi + +for ac_func in fchdir fchown fchmod fsync getcwd getpseudotty \ + getpwent getpwnam getpwuid getrlimit gettimeofday localtime_r lstat \ + memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \ + getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \ + sigprocmask sigvec strcasecmp strcoll strerror strftime stricmp strncasecmp \ + strnicmp strpbrk strptime strtol tgetent towlower towupper iswupper \ + tzset usleep utime utimes mblen ftruncate unsetenv posix_openpt +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for ac_header in sys/select.h sys/socket.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5 +$as_echo_n "checking types of arguments for select... " >&6; } +if ${ac_cv_func_select_args+:} false; then : + $as_echo_n "(cached) " >&6 +else + for ac_arg234 in 'fd_set *' 'int *' 'void *'; do + for ac_arg1 in 'int' 'size_t' 'unsigned long int' 'unsigned int'; do + for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#ifdef HAVE_SYS_SELECT_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +int +main () +{ +extern int select ($ac_arg1, + $ac_arg234, $ac_arg234, $ac_arg234, + $ac_arg5); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done + done +done +# Provide a safe default value. +: "${ac_cv_func_select_args=int,int *,struct timeval *}" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5 +$as_echo "$ac_cv_func_select_args" >&6; } +ac_save_IFS=$IFS; IFS=',' +set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'` +IFS=$ac_save_IFS +shift + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG1 $1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG234 ($2) +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG5 ($3) +_ACEOF + +rm -f conftest* + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 +$as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } +if ${ac_cv_sys_largefile_source+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include /* for off_t */ + #include +int +main () +{ +int (*fp) (FILE *, off_t, int) = fseeko; + return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_sys_largefile_source=no; break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGEFILE_SOURCE 1 +#include /* for off_t */ + #include +int +main () +{ +int (*fp) (FILE *, off_t, int) = fseeko; + return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_sys_largefile_source=1; break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_cv_sys_largefile_source=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 +$as_echo "$ac_cv_sys_largefile_source" >&6; } +case $ac_cv_sys_largefile_source in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source +_ACEOF +;; +esac +rm -rf conftest* + +# We used to try defining _XOPEN_SOURCE=500 too, to work around a bug +# in glibc 2.1.3, but that breaks too many other things. +# If you want fseeko and ftello with glibc, upgrade to a fixed glibc. +if test $ac_cv_sys_largefile_source != unknown; then + +$as_echo "#define HAVE_FSEEKO 1" >>confdefs.h + +fi + + +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if ${ac_cv_sys_file_offset_bits+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if ${ac_cv_sys_large_files+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi + + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-canberra argument" >&5 +$as_echo_n "checking --enable-canberra argument... " >&6; } +# Check whether --enable-canberra was given. +if test "${enable_canberra+set}" = set; then : + enableval=$enable_canberra; +else + enable_canberra="maybe" +fi + + +if test "$enable_canberra" = "maybe"; then + if test "$features" = "huge"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to yes" >&5 +$as_echo "Defaulting to yes" >&6; } + enable_canberra="yes" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to no" >&5 +$as_echo "Defaulting to no" >&6; } + enable_canberra="no" + fi +else + if test "$enable_canberra" = "yes" -a "$has_eval" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot use sound with tiny features" >&5 +$as_echo "cannot use sound with tiny features" >&6; } + enable_canberra="no" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_canberra" >&5 +$as_echo "$enable_canberra" >&6; } + fi +fi +if test "$enable_canberra" = "yes"; then + if test "x$PKG_CONFIG" != "xno"; then + canberra_lib=`$PKG_CONFIG --libs libcanberra 2>/dev/null` + canberra_cflags=`$PKG_CONFIG --cflags libcanberra 2>/dev/null` + fi + if test "x$canberra_lib" = "x"; then + canberra_lib=-lcanberra + canberra_cflags=-D_REENTRANT + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcanberra" >&5 +$as_echo_n "checking for libcanberra... " >&6; } + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + if `echo "$CFLAGS" | grep -v "$canberra_cflags" 2>/dev/null`; then + CFLAGS="$CFLAGS $canberra_cflags" + fi + LIBS="$LIBS $canberra_lib" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + # include + +int +main () +{ + + ca_context *hello; + ca_context_create(&hello); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_CANBERRA 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no; try installing libcanberra-dev" >&5 +$as_echo "no; try installing libcanberra-dev" >&6; }; CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-libsodium argument" >&5 +$as_echo_n "checking --enable-libsodium argument... " >&6; } +# Check whether --enable-libsodium was given. +if test "${enable_libsodium+set}" = set; then : + enableval=$enable_libsodium; +else + enable_libsodium="maybe" +fi + + +if test "$enable_libsodium" = "maybe"; then + if test "$features" = "huge"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to yes" >&5 +$as_echo "Defaulting to yes" >&6; } + enable_libsodium="yes" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to no" >&5 +$as_echo "Defaulting to no" >&6; } + enable_libsodium="no" + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libsodium" >&5 +$as_echo "$enable_libsodium" >&6; } +fi +if test "$enable_libsodium" = "yes"; then + if test "x$PKG_CONFIG" != "xno"; then + libsodium_lib=`$PKG_CONFIG --libs libsodium 2>/dev/null` + libsodium_cflags=`$PKG_CONFIG --cflags libsodium 2>/dev/null` + fi + if test "x$libsodium_lib" = "x"; then + libsodium_lib=-lsodium + libsodium_cflags= + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libsodium" >&5 +$as_echo_n "checking for libsodium... " >&6; } + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $libsodium_cflags" + LIBS="$LIBS $libsodium_lib" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + # include + +int +main () +{ + + printf("%d", sodium_init()); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_SODIUM 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no; try installing libsodium-dev" >&5 +$as_echo "no; try installing libsodium-dev" >&6; }; CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for st_blksize" >&5 +$as_echo_n "checking for st_blksize... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ + struct stat st; + int n; + + stat("/", &st); + n = (int)st.st_blksize; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_ST_BLKSIZE 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for timer_create without -lrt" >&5 +$as_echo_n "checking for timer_create without -lrt... " >&6; } +if ${vim_cv_timer_create+:} false; then : + $as_echo_n "(cached) " >&6 +else + +if test "$cross_compiling" = yes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: failed to build test program; if cross-compiling please set 'vim_cv_timer_create'" >&5 +$as_echo "$as_me: WARNING: failed to build test program; if cross-compiling please set 'vim_cv_timer_create'" >&2;} + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if STDC_HEADERS +# include +# include +#endif +#include +#include +static void set_flag(union sigval sv) {} + +int +main () +{ + + struct timespec ts; + struct sigevent action = {0}; + timer_t timer_id; + + action.sigev_notify = SIGEV_THREAD; + action.sigev_notify_function = set_flag; + if (timer_create(CLOCK_MONOTONIC, &action, &timer_id) < 0) + exit(1); // cannot create a monotonic timer + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + vim_cv_timer_create=yes +else + vim_cv_timer_create=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_timer_create" >&5 +$as_echo "$vim_cv_timer_create" >&6; } + +if test "x$vim_cv_timer_create" = "xno" ; then + save_LIBS="$LIBS" + LIBS="$LIBS -lrt" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for timer_create with -lrt" >&5 +$as_echo_n "checking for timer_create with -lrt... " >&6; } +if ${vim_cv_timer_create_with_lrt+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: failed to build test program; if cross-compiling please set 'vim_cv_timer_create_with_lrt'" >&5 +$as_echo "$as_me: WARNING: failed to build test program; if cross-compiling please set 'vim_cv_timer_create_with_lrt'" >&2;} + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #if STDC_HEADERS + # include + # include + #endif + #include + #include + static void set_flag(union sigval sv) {} + +int +main () +{ + + struct timespec ts; + struct sigevent action = {0}; + timer_t timer_id; + + action.sigev_notify = SIGEV_THREAD; + action.sigev_notify_function = set_flag; + if (timer_create(CLOCK_MONOTONIC, &action, &timer_id) < 0) + exit(1); // cannot create a monotonic timer + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + vim_cv_timer_create_with_lrt=yes +else + vim_cv_timer_create_with_lrt=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_timer_create_with_lrt" >&5 +$as_echo "$vim_cv_timer_create_with_lrt" >&6; } + LIBS="$save_LIBS" +else + vim_cv_timer_create_with_lrt=no +fi + +if test "x$vim_cv_timer_create" = "xyes" ; then + $as_echo "#define HAVE_TIMER_CREATE 1" >>confdefs.h + +fi +if test "x$vim_cv_timer_create_with_lrt" = "xyes" ; then + $as_echo "#define HAVE_TIMER_CREATE 1" >>confdefs.h + + LIBS="$LIBS -lrt" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat() ignores a trailing slash" >&5 +$as_echo_n "checking whether stat() ignores a trailing slash... " >&6; } +if ${vim_cv_stat_ignores_slash+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + + as_fn_error $? "cross-compiling: please set 'vim_cv_stat_ignores_slash'" "$LINENO" 5 + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include "confdefs.h" +#if STDC_HEADERS +# include +# include +#endif +#include +#include +int main() {struct stat st; exit(stat("configure/", &st) != 0); } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + + vim_cv_stat_ignores_slash=yes + +else + + vim_cv_stat_ignores_slash=no + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_stat_ignores_slash" >&5 +$as_echo "$vim_cv_stat_ignores_slash" >&6; } + +if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then + $as_echo "#define STAT_IGNORES_SLASH 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanoseconds field of struct stat" >&5 +$as_echo_n "checking for nanoseconds field of struct stat... " >&6; } +if ${ac_cv_struct_st_mtim_nsec+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CPPFLAGS="$CPPFLAGS" + ac_cv_struct_st_mtim_nsec=no + # st_mtim.tv_nsec -- the usual case + # st_mtim._tv_nsec -- Solaris 2.6, if + # (defined _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED == 1 + # && !defined __EXTENSIONS__) + # st_mtim.st__tim.tv_nsec -- UnixWare 2.1.2 + # st_mtime_n -- AIX 5.2 and above + # st_mtimespec.tv_nsec -- Darwin (Mac OSX) + for ac_val in st_mtim.tv_nsec st_mtim._tv_nsec st_mtim.st__tim.tv_nsec st_mtime_n st_mtimespec.tv_nsec; do + CPPFLAGS="$ac_save_CPPFLAGS -DST_MTIM_NSEC=$ac_val" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +struct stat s; s.ST_MTIM_NSEC; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_struct_st_mtim_nsec=$ac_val; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done + CPPFLAGS="$ac_save_CPPFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_st_mtim_nsec" >&5 +$as_echo "$ac_cv_struct_st_mtim_nsec" >&6; } +if test $ac_cv_struct_st_mtim_nsec != no; then + +cat >>confdefs.h <<_ACEOF +#define ST_MTIM_NSEC $ac_cv_struct_st_mtim_nsec +_ACEOF + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv_open()" >&5 +$as_echo_n "checking for iconv_open()... " >&6; } +save_LIBS="$LIBS" +LIBS="$LIBS -liconv" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_ICONV_H +# include +#endif + +int +main () +{ +iconv_open("fr", "to"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; with -liconv" >&5 +$as_echo "yes; with -liconv" >&6; }; $as_echo "#define HAVE_ICONV 1" >>confdefs.h + +else + LIBS="$save_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_ICONV_H +# include +#endif + +int +main () +{ +iconv_open("fr", "to"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_ICONV 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo(CODESET)" >&5 +$as_echo_n "checking for nl_langinfo(CODESET)... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_LANGINFO_H +# include +#endif + +int +main () +{ +char *cs = nl_langinfo(CODESET); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_NL_LANGINFO_CODESET 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtod in -lm" >&5 +$as_echo_n "checking for strtod in -lm... " >&6; } +if ${ac_cv_lib_m_strtod+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char strtod (); +int +main () +{ +return strtod (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_strtod=yes +else + ac_cv_lib_m_strtod=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_strtod" >&5 +$as_echo "$ac_cv_lib_m_strtod" >&6; } +if test "x$ac_cv_lib_m_strtod" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBM 1 +_ACEOF + + LIBS="-lm $LIBS" + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf()" >&5 +$as_echo_n "checking for isinf()... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_MATH_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif + +int +main () +{ +int r = isinf(1.11); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_ISINF 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnan()" >&5 +$as_echo_n "checking for isnan()... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_MATH_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif + +int +main () +{ +int r = isnan(1.11); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_ISNAN 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-acl argument" >&5 +$as_echo_n "checking --disable-acl argument... " >&6; } +# Check whether --enable-acl was given. +if test "${enable_acl+set}" = set; then : + enableval=$enable_acl; +else + enable_acl="yes" +fi + +if test "$enable_acl" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for acl_get_file in -lposix1e" >&5 +$as_echo_n "checking for acl_get_file in -lposix1e... " >&6; } +if ${ac_cv_lib_posix1e_acl_get_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lposix1e $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char acl_get_file (); +int +main () +{ +return acl_get_file (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_posix1e_acl_get_file=yes +else + ac_cv_lib_posix1e_acl_get_file=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix1e_acl_get_file" >&5 +$as_echo "$ac_cv_lib_posix1e_acl_get_file" >&6; } +if test "x$ac_cv_lib_posix1e_acl_get_file" = xyes; then : + LIBS="$LIBS -lposix1e" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for acl_get_file in -lacl" >&5 +$as_echo_n "checking for acl_get_file in -lacl... " >&6; } +if ${ac_cv_lib_acl_acl_get_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lacl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char acl_get_file (); +int +main () +{ +return acl_get_file (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_acl_acl_get_file=yes +else + ac_cv_lib_acl_acl_get_file=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_acl_acl_get_file" >&5 +$as_echo "$ac_cv_lib_acl_acl_get_file" >&6; } +if test "x$ac_cv_lib_acl_acl_get_file" = xyes; then : + LIBS="$LIBS -lacl" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgetxattr in -lattr" >&5 +$as_echo_n "checking for fgetxattr in -lattr... " >&6; } +if ${ac_cv_lib_attr_fgetxattr+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lattr $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char fgetxattr (); +int +main () +{ +return fgetxattr (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_attr_fgetxattr=yes +else + ac_cv_lib_attr_fgetxattr=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_attr_fgetxattr" >&5 +$as_echo "$ac_cv_lib_attr_fgetxattr" >&6; } +if test "x$ac_cv_lib_attr_fgetxattr" = xyes; then : + LIBS="$LIBS -lattr" +fi + +fi + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for POSIX ACL support" >&5 +$as_echo_n "checking for POSIX ACL support... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_SYS_ACL_H +# include +#endif +acl_t acl; +int +main () +{ +acl = acl_get_file("foo", ACL_TYPE_ACCESS); + acl_set_file("foo", ACL_TYPE_ACCESS, acl); + acl_free(acl); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_POSIX_ACL 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for acl_get in -lsec" >&5 +$as_echo_n "checking for acl_get in -lsec... " >&6; } +if ${ac_cv_lib_sec_acl_get+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsec $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char acl_get (); +int +main () +{ +return acl_get (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_sec_acl_get=yes +else + ac_cv_lib_sec_acl_get=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sec_acl_get" >&5 +$as_echo "$ac_cv_lib_sec_acl_get" >&6; } +if test "x$ac_cv_lib_sec_acl_get" = xyes; then : + LIBS="$LIBS -lsec"; $as_echo "#define HAVE_SOLARIS_ZFS_ACL 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Solaris ACL support" >&5 +$as_echo_n "checking for Solaris ACL support... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_SYS_ACL_H +# include +#endif +int +main () +{ +acl("foo", GETACLCNT, 0, NULL); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_SOLARIS_ACL 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AIX ACL support" >&5 +$as_echo_n "checking for AIX ACL support... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if STDC_HEADERS +# include +# include +#endif +#ifdef HAVE_SYS_ACL_H +# include +#endif +#ifdef HAVE_SYS_ACCESS_H +# include +#endif +#define _ALL_SOURCE + +#include + +int aclsize; +struct acl *aclent; +int +main () +{ +aclsize = sizeof(struct acl); + aclent = (void *)malloc(aclsize); + statacl("foo", STX_NORMAL, aclent, aclsize); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_AIX_ACL 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi + +if test "x$GTK_CFLAGS" != "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pango_shape_full" >&5 +$as_echo_n "checking for pango_shape_full... " >&6; } + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + pango_shape_full(NULL, 0, NULL, 0, NULL, NULL); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_PANGO_SHAPE_FULL 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-gpm argument" >&5 +$as_echo_n "checking --enable-gpm argument... " >&6; } +# Check whether --enable-gpm was given. +if test "${enable_gpm+set}" = set; then : + enableval=$enable_gpm; +else + enable_gpm="yes" +fi + + +if test "$enable_gpm" = "yes" -o "$enable_gpm" = "dynamic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gpm" >&5 +$as_echo "$enable_gpm" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gpm" >&5 +$as_echo_n "checking for gpm... " >&6; } +if ${vi_cv_have_gpm+:} false; then : + $as_echo_n "(cached) " >&6 +else + olibs="$LIBS" ; LIBS="-lgpm" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include +int +main () +{ +Gpm_GetLibVersion(NULL); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + vi_cv_have_gpm=yes +else + vi_cv_have_gpm=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$olibs" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_have_gpm" >&5 +$as_echo "$vi_cv_have_gpm" >&6; } + if test $vi_cv_have_gpm = yes; then + if test "$enable_gpm" = "yes"; then + LIBS="$LIBS -lgpm" + else + $as_echo "#define DYNAMIC_GPM 1" >>confdefs.h + + fi + $as_echo "#define HAVE_GPM 1" >>confdefs.h + + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-sysmouse argument" >&5 +$as_echo_n "checking --disable-sysmouse argument... " >&6; } +# Check whether --enable-sysmouse was given. +if test "${enable_sysmouse+set}" = set; then : + enableval=$enable_sysmouse; +else + enable_sysmouse="yes" +fi + + +if test "$enable_sysmouse" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysmouse" >&5 +$as_echo_n "checking for sysmouse... " >&6; } +if ${vi_cv_have_sysmouse+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include +int +main () +{ +struct mouse_info mouse; + mouse.operation = MOUSE_MODE; + mouse.operation = MOUSE_SHOW; + mouse.u.mode.mode = 0; + mouse.u.mode.signal = SIGUSR2; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + vi_cv_have_sysmouse=yes +else + vi_cv_have_sysmouse=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_have_sysmouse" >&5 +$as_echo "$vi_cv_have_sysmouse" >&6; } + if test $vi_cv_have_sysmouse = yes; then + $as_echo "#define HAVE_SYSMOUSE 1" >>confdefs.h + + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for FD_CLOEXEC" >&5 +$as_echo_n "checking for FD_CLOEXEC... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if HAVE_FCNTL_H +# include +#endif +int +main () +{ + int flag = FD_CLOEXEC; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_FD_CLOEXEC 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5 +$as_echo "not usable" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rename" >&5 +$as_echo_n "checking for rename... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +rename("this", "that") + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_RENAME 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dirfd" >&5 +$as_echo_n "checking for dirfd... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +DIR * dir=opendir("dirname"); dirfd(dir); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_DIRFD 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5 +$as_echo "not usable" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock" >&5 +$as_echo_n "checking for flock... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +flock(10, LOCK_SH); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_FLOCK 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5 +$as_echo "not usable" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysctl" >&5 +$as_echo_n "checking for sysctl... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ + int mib[2], r; + size_t len; + + mib[0] = CTL_HW; + mib[1] = HW_USERMEM; + len = sizeof(r); + (void)sysctl(mib, 2, &r, &len, (void *)0, (size_t)0); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSCTL 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5 +$as_echo "not usable" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysinfo" >&5 +$as_echo_n "checking for sysinfo... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ + struct sysinfo sinfo; + int t; + + (void)sysinfo(&sinfo); + t = sinfo.totalram; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSINFO 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5 +$as_echo "not usable" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysinfo.mem_unit" >&5 +$as_echo_n "checking for sysinfo.mem_unit... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ + struct sysinfo sinfo; + sinfo.mem_unit = 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSINFO_MEM_UNIT 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysinfo.uptime" >&5 +$as_echo_n "checking for sysinfo.uptime... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ + struct sysinfo sinfo; + long ut; + + (void)sysinfo(&sinfo); + ut = sinfo.uptime; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSINFO_UPTIME 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysconf" >&5 +$as_echo_n "checking for sysconf... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + (void)sysconf(_SC_PAGESIZE); + (void)sysconf(_SC_PHYS_PAGES); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSCONF 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5 +$as_echo "not usable" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _SC_SIGSTKSZ via sysconf()" >&5 +$as_echo_n "checking for _SC_SIGSTKSZ via sysconf()... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + (void)sysconf(_SC_SIGSTKSZ); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSCONF_SIGSTKSZ 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5 +$as_echo "not usable" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 +$as_echo_n "checking size of int... " >&6; } +if ${ac_cv_sizeof_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_int" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (int) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_int=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 +$as_echo "$ac_cv_sizeof_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +$as_echo_n "checking size of long... " >&6; } +if ${ac_cv_sizeof_long+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_long" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (long) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_long=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 +$as_echo "$ac_cv_sizeof_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 +$as_echo_n "checking size of time_t... " >&6; } +if ${ac_cv_sizeof_time_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_time_t" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (time_t) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_time_t=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 +$as_echo "$ac_cv_sizeof_time_t" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_TIME_T $ac_cv_sizeof_time_t +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 +$as_echo_n "checking size of off_t... " >&6; } +if ${ac_cv_sizeof_off_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_off_t" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (off_t) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_off_t=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 +$as_echo "$ac_cv_sizeof_off_t" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_OFF_T $ac_cv_sizeof_off_t +_ACEOF + + + +cat >>confdefs.h <<_ACEOF +#define VIM_SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define VIM_SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking uint32_t is 32 bits" >&5 +$as_echo_n "checking uint32_t is 32 bits... " >&6; } +if test "$cross_compiling" = yes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check uint32_t when cross-compiling." >&5 +$as_echo "$as_me: WARNING: cannot check uint32_t when cross-compiling." >&2;} +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +int main() { + uint32_t nr1 = (uint32_t)-1; + uint32_t nr2 = (uint32_t)0xffffffffUL; + if (sizeof(uint32_t) != 4 || nr1 != 0xffffffffUL || nr2 + 1 != 0) return 1; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +else + as_fn_error $? "WRONG! uint32_t not defined correctly." "$LINENO" 5 +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + + +bcopy_test_prog=' +#include "confdefs.h" +#ifdef HAVE_STRING_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif +int main() { + char buf[10]; + strcpy(buf, "abcdefghi"); + mch_memmove(buf, buf + 2, 3); + if (strncmp(buf, "ababcf", 6)) + exit(1); + strcpy(buf, "abcdefghi"); + mch_memmove(buf + 2, buf, 3); + if (strncmp(buf, "cdedef", 6)) + exit(1); + exit(0); /* libc version works properly. */ +}' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether memmove handles overlaps" >&5 +$as_echo_n "checking whether memmove handles overlaps... " >&6; } +if ${vim_cv_memmove_handles_overlap+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + + as_fn_error $? "cross-compiling: please set 'vim_cv_memmove_handles_overlap'" "$LINENO" 5 + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define mch_memmove(s,d,l) memmove(d,s,l) $bcopy_test_prog +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + + vim_cv_memmove_handles_overlap=yes + +else + + vim_cv_memmove_handles_overlap=no + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_memmove_handles_overlap" >&5 +$as_echo "$vim_cv_memmove_handles_overlap" >&6; } + +if test "x$vim_cv_memmove_handles_overlap" = "xyes" ; then + $as_echo "#define USEMEMMOVE 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bcopy handles overlaps" >&5 +$as_echo_n "checking whether bcopy handles overlaps... " >&6; } +if ${vim_cv_bcopy_handles_overlap+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + + as_fn_error $? "cross-compiling: please set 'vim_cv_bcopy_handles_overlap'" "$LINENO" 5 + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define mch_bcopy(s,d,l) bcopy(d,s,l) $bcopy_test_prog +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + + vim_cv_bcopy_handles_overlap=yes + +else + + vim_cv_bcopy_handles_overlap=no + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_bcopy_handles_overlap" >&5 +$as_echo "$vim_cv_bcopy_handles_overlap" >&6; } + + if test "x$vim_cv_bcopy_handles_overlap" = "xyes" ; then + $as_echo "#define USEBCOPY 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether memcpy handles overlaps" >&5 +$as_echo_n "checking whether memcpy handles overlaps... " >&6; } +if ${vim_cv_memcpy_handles_overlap+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + + as_fn_error $? "cross-compiling: please set 'vim_cv_memcpy_handles_overlap'" "$LINENO" 5 + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define mch_memcpy(s,d,l) memcpy(d,s,l) $bcopy_test_prog +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + + vim_cv_memcpy_handles_overlap=yes + +else + + vim_cv_memcpy_handles_overlap=no + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_memcpy_handles_overlap" >&5 +$as_echo "$vim_cv_memcpy_handles_overlap" >&6; } + + if test "x$vim_cv_memcpy_handles_overlap" = "xyes" ; then + $as_echo "#define USEMEMCPY 1" >>confdefs.h + + fi + fi +fi + + +if test "x$with_x" = "xyes"; then + cflags_save=$CFLAGS + libs_save=$LIBS + LIBS="$LIBS $X_LIBS $GUI_LIB_LOC $GUI_X_LIBS $X_PRE_LIBS $X_LIB $X_EXTRA_LIBS" + CFLAGS="$CFLAGS $X_CFLAGS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether X_LOCALE needed" >&5 +$as_echo_n "checking whether X_LOCALE needed... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char _Xsetlocale (); +int +main () +{ +return _Xsetlocale (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define X_LOCALE 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Xutf8SetWMProperties() can be used" >&5 +$as_echo_n "checking whether Xutf8SetWMProperties() can be used... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char Xutf8SetWMProperties (); +int +main () +{ +return Xutf8SetWMProperties (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define HAVE_XUTF8SETWMPROPERTIES 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + CFLAGS=$cflags_save + LIBS=$libs_save +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _xpg4_setrunelocale in -lxpg4" >&5 +$as_echo_n "checking for _xpg4_setrunelocale in -lxpg4... " >&6; } +if ${ac_cv_lib_xpg4__xpg4_setrunelocale+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lxpg4 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char _xpg4_setrunelocale (); +int +main () +{ +return _xpg4_setrunelocale (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_xpg4__xpg4_setrunelocale=yes +else + ac_cv_lib_xpg4__xpg4_setrunelocale=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xpg4__xpg4_setrunelocale" >&5 +$as_echo "$ac_cv_lib_xpg4__xpg4_setrunelocale" >&6; } +if test "x$ac_cv_lib_xpg4__xpg4_setrunelocale" = xyes; then : + LIBS="$LIBS -lxpg4" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create tags" >&5 +$as_echo_n "checking how to create tags... " >&6; } +test -f tags && mv tags tags.save +if (eval ctags --version /dev/null | grep Exuberant) < /dev/null 1>&5 2>&1; then + TAGPRG="ctags -I INIT+,INIT2+,INIT3+,INIT4+,INIT5+ --fields=+S" +elif (eval exctags --version /dev/null | grep Exuberant) < /dev/null 1>&5 2>&1; then + TAGPRG="exctags -I INIT+,INIT2+,INIT3+,INIT4+,INIT5+ --fields=+S" +elif (eval exuberant-ctags --version /dev/null | grep Exuberant) < /dev/null 1>&5 2>&1; then + TAGPRG="exuberant-ctags -I INIT+,INIT2+,INIT3+,INIT4+,INIT5+ --fields=+S" +else + TAGPRG="ctags" + (eval etags /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="etags" + (eval etags -c /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="etags -c" + (eval ctags /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="ctags" + (eval ctags -t /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="ctags -t" + (eval ctags -ts /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="ctags -ts" + (eval ctags -tvs /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="ctags -tvs" + (eval ctags -i+m /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="ctags -i+m" +fi +test -f tags.save && mv tags.save tags +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TAGPRG" >&5 +$as_echo "$TAGPRG" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run man with a section nr" >&5 +$as_echo_n "checking how to run man with a section nr... " >&6; } +MANDEF="man" +(eval MANPAGER=cat PAGER=cat man -s 2 read) < /dev/null > /dev/null 2>&5 && MANDEF="man -s" +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANDEF" >&5 +$as_echo "$MANDEF" >&6; } +if test "$MANDEF" = "man -s"; then + $as_echo "#define USEMAN_S 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-nls argument" >&5 +$as_echo_n "checking --disable-nls argument... " >&6; } +# Check whether --enable-nls was given. +if test "${enable_nls+set}" = set; then : + enableval=$enable_nls; +else + enable_nls="yes" +fi + + +if test "$enable_nls" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + INSTALL_LANGS=install-languages + + INSTALL_TOOL_LANGS=install-tool-languages + + + # Extract the first word of "msgfmt", so it can be a program name with args. +set dummy msgfmt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MSGFMT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MSGFMT"; then + ac_cv_prog_MSGFMT="$MSGFMT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MSGFMT="msgfmt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MSGFMT=$ac_cv_prog_MSGFMT +if test -n "$MSGFMT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 +$as_echo "$MSGFMT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NLS" >&5 +$as_echo_n "checking for NLS... " >&6; } + if test -f po/Makefile; then + have_gettext="no" + if test -n "$MSGFMT"; then + olibs=$LIBS + LIBS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +gettext("Test"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gettext() works" >&5 +$as_echo "gettext() works" >&6; }; have_gettext="yes"; LIBS=$olibs +else + LIBS="-lintl" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +gettext("Test"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gettext() works with -lintl" >&5 +$as_echo "gettext() works with -lintl" >&6; }; have_gettext="yes"; + LIBS="$olibs -lintl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gettext() doesn't work" >&5 +$as_echo "gettext() doesn't work" >&6; }; + LIBS=$olibs +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: msgfmt not found - disabled" >&5 +$as_echo "msgfmt not found - disabled" >&6; }; + fi + if test $have_gettext = "yes" -a "x$features" != "xtiny"; then + $as_echo "#define HAVE_GETTEXT 1" >>confdefs.h + + MAKEMO=yes + + for ac_func in bind_textdomain_codeset +do : + ac_fn_c_check_func "$LINENO" "bind_textdomain_codeset" "ac_cv_func_bind_textdomain_codeset" +if test "x$ac_cv_func_bind_textdomain_codeset" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_BIND_TEXTDOMAIN_CODESET 1 +_ACEOF + +fi +done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _nl_msg_cat_cntr" >&5 +$as_echo_n "checking for _nl_msg_cat_cntr... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + extern int _nl_msg_cat_cntr; +int +main () +{ +++_nl_msg_cat_cntr; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_NL_MSG_CAT_CNTR 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if msgfmt supports --desktop" >&5 +$as_echo_n "checking if msgfmt supports --desktop... " >&6; } + MSGFMT_DESKTOP= + if "$MSGFMT" --help | grep -e '--desktop' >/dev/null; then + if "$MSGFMT" --version | grep '0.19.[3-7]$' >/dev/null; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: broken" >&5 +$as_echo "broken" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + MSGFMT_DESKTOP="gvim.desktop vim.desktop" + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no \"po/Makefile\" - disabled" >&5 +$as_echo "no \"po/Makefile\" - disabled" >&6; }; + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi + +ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + DLL=dlfcn.h +else + ac_fn_c_check_header_mongrel "$LINENO" "dl.h" "ac_cv_header_dl_h" "$ac_includes_default" +if test "x$ac_cv_header_dl_h" = xyes; then : + DLL=dl.h +fi + + +fi + + +if test x${DLL} = xdlfcn.h; then + +$as_echo "#define HAVE_DLFCN_H 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen()" >&5 +$as_echo_n "checking for dlopen()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + extern void* dlopen(); + dlopen(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; + +$as_echo "#define HAVE_DLOPEN 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen() in -ldl" >&5 +$as_echo_n "checking for dlopen() in -ldl... " >&6; } + olibs=$LIBS + LIBS="$LIBS -ldl" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + extern void* dlopen(); + dlopen(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; + +$as_echo "#define HAVE_DLOPEN 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; + LIBS=$olibs +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym()" >&5 +$as_echo_n "checking for dlsym()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + extern void* dlsym(); + dlsym(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; + +$as_echo "#define HAVE_DLSYM 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym() in -ldl" >&5 +$as_echo_n "checking for dlsym() in -ldl... " >&6; } + olibs=$LIBS + LIBS="$LIBS -ldl" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + extern void* dlsym(); + dlsym(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; + +$as_echo "#define HAVE_DLSYM 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; + LIBS=$olibs +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +elif test x${DLL} = xdl.h; then + +$as_echo "#define HAVE_DL_H 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load()" >&5 +$as_echo_n "checking for shl_load()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + extern void* shl_load(); + shl_load(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; + +$as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load() in -ldld" >&5 +$as_echo_n "checking for shl_load() in -ldld... " >&6; } + olibs=$LIBS + LIBS="$LIBS -ldld" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + extern void* shl_load(); + shl_load(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; + +$as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; + LIBS=$olibs +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +for ac_header in setjmp.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "setjmp.h" "ac_cv_header_setjmp_h" "$ac_includes_default" +if test "x$ac_cv_header_setjmp_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SETJMP_H 1 +_ACEOF + +fi + +done + + +if test "x$MACOS_X" = "xyes" -a -n "$PERL"; then + if echo $LIBS | grep -e '-ldl' >/dev/null; then + LIBS=`echo $LIBS | sed s/-ldl//` + PERL_LIBS="$PERL_LIBS -ldl" + fi +fi + +if test "$MACOS_X" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need macOS frameworks" >&5 +$as_echo_n "checking whether we need macOS frameworks... " >&6; } + if test "$MACOS_X_DARWIN" = "yes"; then + if test "$features" = "tiny"; then + OS_EXTRA_SRC=`echo "$OS_EXTRA_SRC" | sed -e 's+os_macosx.m++'` + OS_EXTRA_OBJ=`echo "$OS_EXTRA_OBJ" | sed -e 's+objects/os_macosx.o++'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, we need CoreServices" >&5 +$as_echo "yes, we need CoreServices" >&6; } + LIBS="$LIBS -framework CoreServices" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, we need AppKit" >&5 +$as_echo "yes, we need AppKit" >&6; } + LIBS="$LIBS -framework AppKit" + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi +fi + +if `echo "$CFLAGS" | grep -v D_REENTRANT >/dev/null`; then + CFLAGS="$CFLAGS -D_REENTRANT" +fi + +DEPEND_CFLAGS_FILTER= +if test "$GCC" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC 3 or later" >&5 +$as_echo_n "checking for GCC 3 or later... " >&6; } + gccmajor=`echo "$gccversion" | sed -e 's/^\([1-9][0-9]*\)\..*$/\1/g'` + if test "$gccmajor" -gt "2"; then + DEPEND_CFLAGS_FILTER="| sed 's+-I */+-isystem /+g'" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need -D_FORTIFY_SOURCE=1" >&5 +$as_echo_n "checking whether we need -D_FORTIFY_SOURCE=1... " >&6; } + if test "$gccmajor" -gt "3"; then + CFLAGS=`echo "$CFLAGS" | sed -e 's/-D_FORTIFY_SOURCE=.,//g' -e 's/ *-Wp,-D_FORTIFY_SOURCE=. / /g' -e 's/,-D_FORTIFY_SOURCE=. //g' -e 's/ *-D_FORTIFY_SOURCE=.//g' -e 's/ *-Wp,-U_FORTIFY_SOURCE/ /g' -e 's/ *-U_FORTIFY_SOURCE//g' -e 's/$/ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1/'` + CPPFLAGS=`echo "$CPPFLAGS" | sed -e 's/-D_FORTIFY_SOURCE=.,//g' -e 's/ *-Wp,-D_FORTIFY_SOURCE=. / /g' -e 's/,-D_FORTIFY_SOURCE=. //g' -e 's/ *-D_FORTIFY_SOURCE=.//g' -e 's/ *-Wp,-U_FORTIFY_SOURCE/ /g' -e 's/ *-U_FORTIFY_SOURCE//g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need to force -D_FILE_OFFSET_BITS=64" >&5 +$as_echo_n "checking whether we need to force -D_FILE_OFFSET_BITS=64... " >&6; } +if echo "$CFLAGS $LUA_CFLAGS $MZSCHEME_CFLAGS $PERL_CFLAGS $PYTHON_CFLAGS $PYTHON3_CFLAGS $TCL_CFLAGS $RUBY_CFLAGS $GTK_CFLAGS" | grep -q D_FILE_OFFSET_BITS 2>/dev/null; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define _FILE_OFFSET_BITS 64" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +LDFLAGS=`echo "$LDFLAGS" | sed -e 's/-L /-L/g'` + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker --as-needed support" >&5 +$as_echo_n "checking linker --as-needed support... " >&6; } +LINK_AS_NEEDED= +# Check if linker supports --as-needed and --no-as-needed options +if $CC -Wl,--help 2>/dev/null | grep as-needed > /dev/null; then + if ! echo "$LDFLAGS" | grep -q -- '-Wl,[^[:space:]]*--as-needed'; then + LDFLAGS="$LDFLAGS -Wl,--as-needed" + fi + LINK_AS_NEEDED=yes +fi +if test "$LINK_AS_NEEDED" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# IBM z/OS reset CFLAGS for config.mk +if test "$zOSUnix" = "yes"; then + CFLAGS="-D_ALL_SOURCE -Wc,float\(ieee\),dll" +fi + +ac_config_files="$ac_config_files auto/config.mk:config.mk.in" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>auto/config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "auto/config.h") CONFIG_HEADERS="$CONFIG_HEADERS auto/config.h:config.h.in" ;; + "auto/config.mk") CONFIG_FILES="$CONFIG_FILES auto/config.mk:config.mk.in" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>auto/config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + diff --git a/src/autocmd.c b/src/autocmd.c new file mode 100644 index 0000000..a409379 --- /dev/null +++ b/src/autocmd.c @@ -0,0 +1,3274 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * autocmd.c: Autocommand related functions + */ + +#include "vim.h" + +/* + * The autocommands are stored in a list for each event. + * Autocommands for the same pattern, that are consecutive, are joined + * together, to avoid having to match the pattern too often. + * The result is an array of Autopat lists, which point to AutoCmd lists: + * + * last_autopat[0] -----------------------------+ + * V + * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL + * Autopat.cmds Autopat.cmds + * | | + * V V + * AutoCmd.next AutoCmd.next + * | | + * V V + * AutoCmd.next NULL + * | + * V + * NULL + * + * last_autopat[1] --------+ + * V + * first_autopat[1] --> Autopat.next --> NULL + * Autopat.cmds + * | + * V + * AutoCmd.next + * | + * V + * NULL + * etc. + * + * The order of AutoCmds is important, this is the order in which they were + * defined and will have to be executed. + */ +typedef struct AutoCmd +{ + char_u *cmd; // The command to be executed (NULL + // when command has been removed). + char once; // "One shot": removed after execution + char nested; // If autocommands nest here. + char last; // last command in list + sctx_T script_ctx; // script context where it is defined + struct AutoCmd *next; // next AutoCmd in list +} AutoCmd; + +typedef struct AutoPat +{ + struct AutoPat *next; // Next AutoPat in AutoPat list; MUST + // be the first entry. + char_u *pat; // pattern as typed (NULL when pattern + // has been removed) + regprog_T *reg_prog; // compiled regprog for pattern + AutoCmd *cmds; // list of commands to do + int group; // group ID + int patlen; // strlen() of pat + int buflocal_nr; // !=0 for buffer-local AutoPat + char allow_dirs; // Pattern may match whole path + char last; // last pattern for apply_autocmds() +} AutoPat; + +static struct event_name +{ + char *name; // event name + event_T event; // event number +} event_names[] = +{ + {"BufAdd", EVENT_BUFADD}, + {"BufCreate", EVENT_BUFADD}, + {"BufDelete", EVENT_BUFDELETE}, + {"BufEnter", EVENT_BUFENTER}, + {"BufFilePost", EVENT_BUFFILEPOST}, + {"BufFilePre", EVENT_BUFFILEPRE}, + {"BufHidden", EVENT_BUFHIDDEN}, + {"BufLeave", EVENT_BUFLEAVE}, + {"BufNew", EVENT_BUFNEW}, + {"BufNewFile", EVENT_BUFNEWFILE}, + {"BufRead", EVENT_BUFREADPOST}, + {"BufReadCmd", EVENT_BUFREADCMD}, + {"BufReadPost", EVENT_BUFREADPOST}, + {"BufReadPre", EVENT_BUFREADPRE}, + {"BufUnload", EVENT_BUFUNLOAD}, + {"BufWinEnter", EVENT_BUFWINENTER}, + {"BufWinLeave", EVENT_BUFWINLEAVE}, + {"BufWipeout", EVENT_BUFWIPEOUT}, + {"BufWrite", EVENT_BUFWRITEPRE}, + {"BufWritePost", EVENT_BUFWRITEPOST}, + {"BufWritePre", EVENT_BUFWRITEPRE}, + {"BufWriteCmd", EVENT_BUFWRITECMD}, + {"CmdlineChanged", EVENT_CMDLINECHANGED}, + {"CmdlineEnter", EVENT_CMDLINEENTER}, + {"CmdlineLeave", EVENT_CMDLINELEAVE}, + {"CmdwinEnter", EVENT_CMDWINENTER}, + {"CmdwinLeave", EVENT_CMDWINLEAVE}, + {"CmdUndefined", EVENT_CMDUNDEFINED}, + {"ColorScheme", EVENT_COLORSCHEME}, + {"ColorSchemePre", EVENT_COLORSCHEMEPRE}, + {"CompleteChanged", EVENT_COMPLETECHANGED}, + {"CompleteDone", EVENT_COMPLETEDONE}, + {"CompleteDonePre", EVENT_COMPLETEDONEPRE}, + {"CursorHold", EVENT_CURSORHOLD}, + {"CursorHoldI", EVENT_CURSORHOLDI}, + {"CursorMoved", EVENT_CURSORMOVED}, + {"CursorMovedI", EVENT_CURSORMOVEDI}, + {"DiffUpdated", EVENT_DIFFUPDATED}, + {"DirChanged", EVENT_DIRCHANGED}, + {"DirChangedPre", EVENT_DIRCHANGEDPRE}, + {"EncodingChanged", EVENT_ENCODINGCHANGED}, + {"ExitPre", EVENT_EXITPRE}, + {"FileEncoding", EVENT_ENCODINGCHANGED}, + {"FileAppendPost", EVENT_FILEAPPENDPOST}, + {"FileAppendPre", EVENT_FILEAPPENDPRE}, + {"FileAppendCmd", EVENT_FILEAPPENDCMD}, + {"FileChangedShell",EVENT_FILECHANGEDSHELL}, + {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST}, + {"FileChangedRO", EVENT_FILECHANGEDRO}, + {"FileReadPost", EVENT_FILEREADPOST}, + {"FileReadPre", EVENT_FILEREADPRE}, + {"FileReadCmd", EVENT_FILEREADCMD}, + {"FileType", EVENT_FILETYPE}, + {"FileWritePost", EVENT_FILEWRITEPOST}, + {"FileWritePre", EVENT_FILEWRITEPRE}, + {"FileWriteCmd", EVENT_FILEWRITECMD}, + {"FilterReadPost", EVENT_FILTERREADPOST}, + {"FilterReadPre", EVENT_FILTERREADPRE}, + {"FilterWritePost", EVENT_FILTERWRITEPOST}, + {"FilterWritePre", EVENT_FILTERWRITEPRE}, + {"FocusGained", EVENT_FOCUSGAINED}, + {"FocusLost", EVENT_FOCUSLOST}, + {"FuncUndefined", EVENT_FUNCUNDEFINED}, + {"GUIEnter", EVENT_GUIENTER}, + {"GUIFailed", EVENT_GUIFAILED}, + {"InsertChange", EVENT_INSERTCHANGE}, + {"InsertEnter", EVENT_INSERTENTER}, + {"InsertLeave", EVENT_INSERTLEAVE}, + {"InsertLeavePre", EVENT_INSERTLEAVEPRE}, + {"InsertCharPre", EVENT_INSERTCHARPRE}, + {"MenuPopup", EVENT_MENUPOPUP}, + {"ModeChanged", EVENT_MODECHANGED}, + {"OptionSet", EVENT_OPTIONSET}, + {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST}, + {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE}, + {"QuitPre", EVENT_QUITPRE}, + {"RemoteReply", EVENT_REMOTEREPLY}, + {"SafeState", EVENT_SAFESTATE}, + {"SafeStateAgain", EVENT_SAFESTATEAGAIN}, + {"SessionLoadPost", EVENT_SESSIONLOADPOST}, + {"ShellCmdPost", EVENT_SHELLCMDPOST}, + {"ShellFilterPost", EVENT_SHELLFILTERPOST}, + {"SigUSR1", EVENT_SIGUSR1}, + {"SourceCmd", EVENT_SOURCECMD}, + {"SourcePre", EVENT_SOURCEPRE}, + {"SourcePost", EVENT_SOURCEPOST}, + {"SpellFileMissing",EVENT_SPELLFILEMISSING}, + {"StdinReadPost", EVENT_STDINREADPOST}, + {"StdinReadPre", EVENT_STDINREADPRE}, + {"SwapExists", EVENT_SWAPEXISTS}, + {"Syntax", EVENT_SYNTAX}, + {"TabNew", EVENT_TABNEW}, + {"TabClosed", EVENT_TABCLOSED}, + {"TabEnter", EVENT_TABENTER}, + {"TabLeave", EVENT_TABLEAVE}, + {"TermChanged", EVENT_TERMCHANGED}, + {"TerminalOpen", EVENT_TERMINALOPEN}, + {"TerminalWinOpen", EVENT_TERMINALWINOPEN}, + {"TermResponse", EVENT_TERMRESPONSE}, + {"TextChanged", EVENT_TEXTCHANGED}, + {"TextChangedI", EVENT_TEXTCHANGEDI}, + {"TextChangedP", EVENT_TEXTCHANGEDP}, + {"TextChangedT", EVENT_TEXTCHANGEDT}, + {"User", EVENT_USER}, + {"VimEnter", EVENT_VIMENTER}, + {"VimLeave", EVENT_VIMLEAVE}, + {"VimLeavePre", EVENT_VIMLEAVEPRE}, + {"WinNew", EVENT_WINNEW}, + {"WinClosed", EVENT_WINCLOSED}, + {"WinEnter", EVENT_WINENTER}, + {"WinLeave", EVENT_WINLEAVE}, + {"WinResized", EVENT_WINRESIZED}, + {"WinScrolled", EVENT_WINSCROLLED}, + {"VimResized", EVENT_VIMRESIZED}, + {"TextYankPost", EVENT_TEXTYANKPOST}, + {"VimSuspend", EVENT_VIMSUSPEND}, + {"VimResume", EVENT_VIMRESUME}, + {NULL, (event_T)0} +}; + +static AutoPat *first_autopat[NUM_EVENTS] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +static AutoPat *last_autopat[NUM_EVENTS] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +#define AUGROUP_DEFAULT (-1) // default autocmd group +#define AUGROUP_ERROR (-2) // erroneous autocmd group +#define AUGROUP_ALL (-3) // all autocmd groups + +/* + * struct used to keep status while executing autocommands for an event. + */ +struct AutoPatCmd_S +{ + AutoPat *curpat; // next AutoPat to examine + AutoCmd *nextcmd; // next AutoCmd to execute + int group; // group being used + char_u *fname; // fname to match with + char_u *sfname; // sfname to match with + char_u *tail; // tail of fname + event_T event; // current event + sctx_T script_ctx; // script context where it is defined + int arg_bufnr; // Initially equal to , set to zero when + // buf is deleted. + AutoPatCmd_T *next; // chain of active apc-s for auto-invalidation +}; + +static AutoPatCmd_T *active_apc_list = NULL; // stack of active autocommands + +// Macro to loop over all the patterns for an autocmd event +#define FOR_ALL_AUTOCMD_PATTERNS(event, ap) \ + for ((ap) = first_autopat[(int)(event)]; (ap) != NULL; (ap) = (ap)->next) + +/* + * augroups stores a list of autocmd group names. + */ +static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL}; +#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i]) +// use get_deleted_augroup() to get this +static char_u *deleted_augroup = NULL; + +/* + * The ID of the current group. Group 0 is the default one. + */ +static int current_augroup = AUGROUP_DEFAULT; + +static int au_need_clean = FALSE; // need to delete marked patterns + +static char_u *event_nr2name(event_T event); +static int au_get_grouparg(char_u **argp); +static int do_autocmd_event(event_T event, char_u *pat, int once, int nested, char_u *cmd, int forceit, int group, int flags); +static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap); +static void auto_next_pat(AutoPatCmd_T *apc, int stop_at_last); +static int au_find_group(char_u *name); + +static event_T last_event; +static int last_group; +static int autocmd_blocked = 0; // block all autocmds + + static char_u * +get_deleted_augroup(void) +{ + if (deleted_augroup == NULL) + deleted_augroup = (char_u *)_("--Deleted--"); + return deleted_augroup; +} + +/* + * Show the autocommands for one AutoPat. + */ + static void +show_autocmd(AutoPat *ap, event_T event) +{ + AutoCmd *ac; + + // Check for "got_int" (here and at various places below), which is set + // when "q" has been hit for the "--more--" prompt + if (got_int) + return; + if (ap->pat == NULL) // pattern has been removed + return; + + // Make sure no info referenced by "ap" is cleared, e.g. when a timer + // clears an augroup. Jump to "theend" after this! + // "ap->pat" may be cleared anyway. + ++autocmd_busy; + + msg_putchar('\n'); + if (got_int) + goto theend; + if (event != last_event || ap->group != last_group) + { + if (ap->group != AUGROUP_DEFAULT) + { + if (AUGROUP_NAME(ap->group) == NULL) + msg_puts_attr((char *)get_deleted_augroup(), HL_ATTR(HLF_E)); + else + msg_puts_attr((char *)AUGROUP_NAME(ap->group), HL_ATTR(HLF_T)); + msg_puts(" "); + } + msg_puts_attr((char *)event_nr2name(event), HL_ATTR(HLF_T)); + last_event = event; + last_group = ap->group; + msg_putchar('\n'); + if (got_int) + goto theend; + } + + if (ap->pat == NULL) + goto theend; // timer might have cleared the pattern or group + + msg_col = 4; + msg_outtrans(ap->pat); + + for (ac = ap->cmds; ac != NULL; ac = ac->next) + { + if (ac->cmd == NULL) // skip removed commands + continue; + + if (msg_col >= 14) + msg_putchar('\n'); + msg_col = 14; + if (got_int) + goto theend; + msg_outtrans(ac->cmd); +#ifdef FEAT_EVAL + if (p_verbose > 0) + last_set_msg(ac->script_ctx); +#endif + if (got_int) + goto theend; + if (ac->next != NULL) + { + msg_putchar('\n'); + if (got_int) + goto theend; + } + } + +theend: + --autocmd_busy; +} + +/* + * Mark an autocommand pattern for deletion. + */ + static void +au_remove_pat(AutoPat *ap) +{ + VIM_CLEAR(ap->pat); + ap->buflocal_nr = -1; + au_need_clean = TRUE; +} + +/* + * Mark all commands for a pattern for deletion. + */ + static void +au_remove_cmds(AutoPat *ap) +{ + AutoCmd *ac; + + for (ac = ap->cmds; ac != NULL; ac = ac->next) + VIM_CLEAR(ac->cmd); + au_need_clean = TRUE; +} + +// Delete one command from an autocmd pattern. +static void au_del_cmd(AutoCmd *ac) +{ + VIM_CLEAR(ac->cmd); + au_need_clean = TRUE; +} + +/* + * Cleanup autocommands and patterns that have been deleted. + * This is only done when not executing autocommands. + */ + static void +au_cleanup(void) +{ + AutoPat *ap, **prev_ap; + AutoCmd *ac, **prev_ac; + event_T event; + + if (autocmd_busy || !au_need_clean) + return; + + // loop over all events + for (event = (event_T)0; (int)event < NUM_EVENTS; + event = (event_T)((int)event + 1)) + { + // loop over all autocommand patterns + prev_ap = &(first_autopat[(int)event]); + for (ap = *prev_ap; ap != NULL; ap = *prev_ap) + { + int has_cmd = FALSE; + + // loop over all commands for this pattern + prev_ac = &(ap->cmds); + for (ac = *prev_ac; ac != NULL; ac = *prev_ac) + { + // remove the command if the pattern is to be deleted or when + // the command has been marked for deletion + if (ap->pat == NULL || ac->cmd == NULL) + { + *prev_ac = ac->next; + vim_free(ac->cmd); + vim_free(ac); + } + else + { + has_cmd = TRUE; + prev_ac = &(ac->next); + } + } + + if (ap->pat != NULL && !has_cmd) + // Pattern was not marked for deletion, but all of its + // commands were. So mark the pattern for deletion. + au_remove_pat(ap); + + // remove the pattern if it has been marked for deletion + if (ap->pat == NULL) + { + if (ap->next == NULL) + { + if (prev_ap == &(first_autopat[(int)event])) + last_autopat[(int)event] = NULL; + else + // this depends on the "next" field being the first in + // the struct + last_autopat[(int)event] = (AutoPat *)prev_ap; + } + *prev_ap = ap->next; + vim_regfree(ap->reg_prog); + vim_free(ap); + } + else + prev_ap = &(ap->next); + } + } + + au_need_clean = FALSE; +} + +/* + * Called when buffer is freed, to remove/invalidate related buffer-local + * autocmds. + */ + void +aubuflocal_remove(buf_T *buf) +{ + AutoPat *ap; + event_T event; + AutoPatCmd_T *apc; + + // invalidate currently executing autocommands + for (apc = active_apc_list; apc; apc = apc->next) + if (buf->b_fnum == apc->arg_bufnr) + apc->arg_bufnr = 0; + + // invalidate buflocals looping through events + for (event = (event_T)0; (int)event < NUM_EVENTS; + event = (event_T)((int)event + 1)) + // loop over all autocommand patterns + FOR_ALL_AUTOCMD_PATTERNS(event, ap) + if (ap->buflocal_nr == buf->b_fnum) + { + au_remove_pat(ap); + if (p_verbose >= 6) + { + verbose_enter(); + smsg(_("auto-removing autocommand: %s "), + event_nr2name(event), buf->b_fnum); + verbose_leave(); + } + } + au_cleanup(); +} + +/* + * Add an autocmd group name. + * Return its ID. Returns AUGROUP_ERROR (< 0) for error. + */ + static int +au_new_group(char_u *name) +{ + int i; + + i = au_find_group(name); + if (i != AUGROUP_ERROR) + return i; + + // the group doesn't exist yet, add it. First try using a free entry. + for (i = 0; i < augroups.ga_len; ++i) + if (AUGROUP_NAME(i) == NULL) + break; + if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL) + return AUGROUP_ERROR; + + AUGROUP_NAME(i) = vim_strsave(name); + if (AUGROUP_NAME(i) == NULL) + return AUGROUP_ERROR; + if (i == augroups.ga_len) + ++augroups.ga_len; + + return i; +} + + static void +au_del_group(char_u *name) +{ + int i; + event_T event; + AutoPat *ap; + int in_use = FALSE; + + + i = au_find_group(name); + if (i == AUGROUP_ERROR) // the group doesn't exist + { + semsg(_(e_no_such_group_str), name); + return; + } + if (i == current_augroup) + { + emsg(_(e_cannot_delete_current_group)); + return; + } + + for (event = (event_T)0; (int)event < NUM_EVENTS; + event = (event_T)((int)event + 1)) + { + FOR_ALL_AUTOCMD_PATTERNS(event, ap) + if (ap->group == i && ap->pat != NULL) + { + give_warning((char_u *)_("W19: Deleting augroup that is still in use"), TRUE); + in_use = TRUE; + event = NUM_EVENTS; + break; + } + } + vim_free(AUGROUP_NAME(i)); + if (in_use) + AUGROUP_NAME(i) = get_deleted_augroup(); + else + AUGROUP_NAME(i) = NULL; +} + +/* + * Find the ID of an autocmd group name. + * Return its ID. Returns AUGROUP_ERROR (< 0) for error. + */ + static int +au_find_group(char_u *name) +{ + int i; + + for (i = 0; i < augroups.ga_len; ++i) + if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup() + && STRCMP(AUGROUP_NAME(i), name) == 0) + return i; + return AUGROUP_ERROR; +} + +/* + * Return TRUE if augroup "name" exists. + */ + int +au_has_group(char_u *name) +{ + return au_find_group(name) != AUGROUP_ERROR; +} + +/* + * ":augroup {name}". + */ + void +do_augroup(char_u *arg, int del_group) +{ + int i; + + if (del_group) + { + if (*arg == NUL) + emsg(_(e_argument_required)); + else + au_del_group(arg); + } + else if (STRICMP(arg, "end") == 0) // ":aug end": back to group 0 + current_augroup = AUGROUP_DEFAULT; + else if (*arg) // ":aug xxx": switch to group xxx + { + i = au_new_group(arg); + if (i != AUGROUP_ERROR) + current_augroup = i; + } + else // ":aug": list the group names + { + msg_start(); + for (i = 0; i < augroups.ga_len; ++i) + { + if (AUGROUP_NAME(i) != NULL) + { + msg_puts((char *)AUGROUP_NAME(i)); + msg_puts(" "); + } + } + msg_clr_eos(); + msg_end(); + } +} + + void +autocmd_init(void) +{ + CLEAR_FIELD(aucmd_win); +} + +#if defined(EXITFREE) || defined(PROTO) + void +free_all_autocmds(void) +{ + char_u *s; + + for (current_augroup = -1; current_augroup < augroups.ga_len; + ++current_augroup) + do_autocmd(NULL, (char_u *)"", TRUE); + + for (int i = 0; i < augroups.ga_len; ++i) + { + s = ((char_u **)(augroups.ga_data))[i]; + if (s != get_deleted_augroup()) + vim_free(s); + } + ga_clear(&augroups); + + // aucmd_win[] is freed in win_free_all() +} +#endif + +/* + * Return TRUE if "win" is an active entry in aucmd_win[]. + */ + int +is_aucmd_win(win_T *win) +{ + for (int i = 0; i < AUCMD_WIN_COUNT; ++i) + if (aucmd_win[i].auc_win_used && aucmd_win[i].auc_win == win) + return TRUE; + return FALSE; +} + +/* + * Return the event number for event name "start". + * Return NUM_EVENTS if the event name was not found. + * Return a pointer to the next event name in "end". + */ + static event_T +event_name2nr(char_u *start, char_u **end) +{ + char_u *p; + int i; + int len; + + // the event name ends with end of line, '|', a blank or a comma + for (p = start; *p && !VIM_ISWHITE(*p) && *p != ',' && *p != '|'; ++p) + ; + for (i = 0; event_names[i].name != NULL; ++i) + { + len = (int)STRLEN(event_names[i].name); + if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0) + break; + } + if (*p == ',') + ++p; + *end = p; + if (event_names[i].name == NULL) + return NUM_EVENTS; + return event_names[i].event; +} + +/* + * Return the name for event "event". + */ + static char_u * +event_nr2name(event_T event) +{ + int i; + + for (i = 0; event_names[i].name != NULL; ++i) + if (event_names[i].event == event) + return (char_u *)event_names[i].name; + return (char_u *)"Unknown"; +} + +/* + * Scan over the events. "*" stands for all events. + */ + static char_u * +find_end_event( + char_u *arg, + int have_group) // TRUE when group name was found +{ + char_u *pat; + char_u *p; + + if (*arg == '*') + { + if (arg[1] && !VIM_ISWHITE(arg[1])) + { + semsg(_(e_illegal_character_after_star_str), arg); + return NULL; + } + pat = arg + 1; + } + else + { + for (pat = arg; *pat && *pat != '|' && !VIM_ISWHITE(*pat); pat = p) + { + if ((int)event_name2nr(pat, &p) >= NUM_EVENTS) + { + if (have_group) + semsg(_(e_no_such_event_str), pat); + else + semsg(_(e_no_such_group_or_event_str), pat); + return NULL; + } + } + } + return pat; +} + +/* + * Return TRUE if "event" is included in 'eventignore'. + */ + static int +event_ignored(event_T event) +{ + char_u *p = p_ei; + + while (*p != NUL) + { + if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ',')) + return TRUE; + if (event_name2nr(p, &p) == event) + return TRUE; + } + + return FALSE; +} + +/* + * Return OK when the contents of p_ei is valid, FAIL otherwise. + */ + int +check_ei(void) +{ + char_u *p = p_ei; + + while (*p) + { + if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ',')) + { + p += 3; + if (*p == ',') + ++p; + } + else if (event_name2nr(p, &p) == NUM_EVENTS) + return FAIL; + } + + return OK; +} + +# if defined(FEAT_SYN_HL) || defined(PROTO) + +/* + * Add "what" to 'eventignore' to skip loading syntax highlighting for every + * buffer loaded into the window. "what" must start with a comma. + * Returns the old value of 'eventignore' in allocated memory. + */ + char_u * +au_event_disable(char *what) +{ + char_u *new_ei; + char_u *save_ei; + + save_ei = vim_strsave(p_ei); + if (save_ei == NULL) + return NULL; + + new_ei = vim_strnsave(p_ei, STRLEN(p_ei) + STRLEN(what)); + if (new_ei == NULL) + { + vim_free(save_ei); + return NULL; + } + + if (*what == ',' && *p_ei == NUL) + STRCPY(new_ei, what + 1); + else + STRCAT(new_ei, what); + set_string_option_direct((char_u *)"ei", -1, new_ei, + OPT_FREE, SID_NONE); + vim_free(new_ei); + return save_ei; +} + + void +au_event_restore(char_u *old_ei) +{ + if (old_ei != NULL) + { + set_string_option_direct((char_u *)"ei", -1, old_ei, + OPT_FREE, SID_NONE); + vim_free(old_ei); + } +} +# endif // FEAT_SYN_HL + +/* + * do_autocmd() -- implements the :autocmd command. Can be used in the + * following ways: + * + * :autocmd Add to the list of commands that + * will be automatically executed for + * when editing a file matching , in + * the current group. + * :autocmd Show the autocommands associated with + * and . + * :autocmd Show the autocommands associated with + * . + * :autocmd Show all autocommands. + * :autocmd! Remove all autocommands associated with + * and , and add the command + * , for the current group. + * :autocmd! Remove all autocommands associated with + * and for the current group. + * :autocmd! Remove all autocommands associated with + * for the current group. + * :autocmd! Remove ALL autocommands for the current + * group. + * + * Multiple events and patterns may be given separated by commas. Here are + * some examples: + * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic + * :autocmd bufleave * set tw=79 nosmartindent ic infercase + * + * :autocmd * *.c show all autocommands for *.c files. + * + * Mostly a {group} argument can optionally appear before . + * "eap" can be NULL. + */ + void +do_autocmd(exarg_T *eap, char_u *arg_in, int forceit) +{ + char_u *arg = arg_in; + char_u *pat; + char_u *envpat = NULL; + char_u *cmd; + int cmd_need_free = FALSE; + event_T event; + char_u *tofree = NULL; + int nested = FALSE; + int once = FALSE; + int group; + int i; + int flags = 0; + + if (*arg == '|') + { + eap->nextcmd = arg + 1; + arg = (char_u *)""; + group = AUGROUP_ALL; // no argument, use all groups + } + else + { + /* + * Check for a legal group name. If not, use AUGROUP_ALL. + */ + group = au_get_grouparg(&arg); + if (arg == NULL) // out of memory + return; + } + + /* + * Scan over the events. + * If we find an illegal name, return here, don't do anything. + */ + pat = find_end_event(arg, group != AUGROUP_ALL); + if (pat == NULL) + return; + + pat = skipwhite(pat); + if (*pat == '|') + { + eap->nextcmd = pat + 1; + pat = (char_u *)""; + cmd = (char_u *)""; + } + else + { + /* + * Scan over the pattern. Put a NUL at the end. + */ + cmd = pat; + while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\')) + cmd++; + if (*cmd) + *cmd++ = NUL; + + // Expand environment variables in the pattern. Set 'shellslash', we + // want forward slashes here. + if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL) + { +#ifdef BACKSLASH_IN_FILENAME + int p_ssl_save = p_ssl; + + p_ssl = TRUE; +#endif + envpat = expand_env_save(pat); +#ifdef BACKSLASH_IN_FILENAME + p_ssl = p_ssl_save; +#endif + if (envpat != NULL) + pat = envpat; + } + + cmd = skipwhite(cmd); + for (i = 0; i < 2; i++) + { + if (*cmd == NUL) + continue; + + // Check for "++once" flag. + if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6])) + { + if (once) + semsg(_(e_duplicate_argument_str), "++once"); + once = TRUE; + cmd = skipwhite(cmd + 6); + } + + // Check for "++nested" flag. + if ((STRNCMP(cmd, "++nested", 8) == 0 && VIM_ISWHITE(cmd[8]))) + { + if (nested) + { + semsg(_(e_duplicate_argument_str), "++nested"); + return; + } + nested = TRUE; + cmd = skipwhite(cmd + 8); + } + + // Check for the old "nested" flag in legacy script. + if (STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6])) + { + if (in_vim9script()) + { + // If there ever is a :nested command this error should + // be removed and "nested" accepted as the start of the + // command. + emsg(_(e_invalid_command_nested_did_you_mean_plusplus_nested)); + return; + } + if (nested) + { + semsg(_(e_duplicate_argument_str), "nested"); + return; + } + nested = TRUE; + cmd = skipwhite(cmd + 6); + } + } + + /* + * Find the start of the commands. + * Expand in it. + */ + if (*cmd != NUL) + { + if (eap != NULL) + // Read a {} block if it follows. + cmd = may_get_cmd_block(eap, cmd, &tofree, &flags); + + cmd = expand_sfile(cmd); + if (cmd == NULL) // some error + return; + cmd_need_free = TRUE; + } + } + + /* + * Print header when showing autocommands. + */ + if (!forceit && *cmd == NUL) + // Highlight title + msg_puts_title(_("\n--- Autocommands ---")); + + /* + * Loop over the events. + */ + last_event = (event_T)-1; // for listing the event name + last_group = AUGROUP_ERROR; // for listing the group name + if (*arg == '*' || *arg == NUL || *arg == '|') + { + if (*cmd != NUL) + emsg(_(e_cannot_define_autocommands_for_all_events)); + else + for (event = (event_T)0; (int)event < NUM_EVENTS; + event = (event_T)((int)event + 1)) + if (do_autocmd_event(event, pat, + once, nested, cmd, forceit, group, flags) == FAIL) + break; + } + else + { + while (*arg && *arg != '|' && !VIM_ISWHITE(*arg)) + if (do_autocmd_event(event_name2nr(arg, &arg), pat, + once, nested, cmd, forceit, group, flags) == FAIL) + break; + } + + if (cmd_need_free) + vim_free(cmd); + vim_free(tofree); + vim_free(envpat); +} + +/* + * Find the group ID in a ":autocmd" or ":doautocmd" argument. + * The "argp" argument is advanced to the following argument. + * + * Returns the group ID, AUGROUP_ERROR for error (out of memory). + */ + static int +au_get_grouparg(char_u **argp) +{ + char_u *group_name; + char_u *p; + char_u *arg = *argp; + int group = AUGROUP_ALL; + + for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p) + ; + if (p <= arg) + return AUGROUP_ALL; + + group_name = vim_strnsave(arg, p - arg); + if (group_name == NULL) // out of memory + return AUGROUP_ERROR; + group = au_find_group(group_name); + if (group == AUGROUP_ERROR) + group = AUGROUP_ALL; // no match, use all groups + else + *argp = skipwhite(p); // match, skip over group name + vim_free(group_name); + return group; +} + +/* + * do_autocmd() for one event. + * If *pat == NUL do for all patterns. + * If *cmd == NUL show entries. + * If forceit == TRUE delete entries. + * If group is not AUGROUP_ALL, only use this group. + */ + static int +do_autocmd_event( + event_T event, + char_u *pat, + int once, + int nested, + char_u *cmd, + int forceit, + int group, + int flags) +{ + AutoPat *ap; + AutoPat **prev_ap; + AutoCmd *ac; + AutoCmd **prev_ac; + int brace_level; + char_u *endpat; + int findgroup; + int allgroups; + int patlen; + int is_buflocal; + int buflocal_nr; + char_u buflocal_pat[25]; // for "" + + if (group == AUGROUP_ALL) + findgroup = current_augroup; + else + findgroup = group; + allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL); + + /* + * Show or delete all patterns for an event. + */ + if (*pat == NUL) + { + FOR_ALL_AUTOCMD_PATTERNS(event, ap) + { + if (forceit) // delete the AutoPat, if it's in the current group + { + if (ap->group == findgroup) + au_remove_pat(ap); + } + else if (group == AUGROUP_ALL || ap->group == group) + show_autocmd(ap, event); + } + } + + /* + * Loop through all the specified patterns. + */ + for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat)) + { + /* + * Find end of the pattern. + * Watch out for a comma in braces, like "*.\{obj,o\}". + */ + brace_level = 0; + for (endpat = pat; *endpat && (*endpat != ',' || brace_level + || (endpat > pat && endpat[-1] == '\\')); ++endpat) + { + if (*endpat == '{') + brace_level++; + else if (*endpat == '}') + brace_level--; + } + if (pat == endpat) // ignore single comma + continue; + patlen = (int)(endpat - pat); + + /* + * detect special buffer-local patterns + */ + is_buflocal = FALSE; + buflocal_nr = 0; + + if (patlen >= 8 && STRNCMP(pat, "') + { + // "": Error will be printed only for addition. + // printing and removing will proceed silently. + is_buflocal = TRUE; + if (patlen == 8) + // "" + buflocal_nr = curbuf->b_fnum; + else if (patlen > 9 && pat[7] == '=') + { + if (patlen == 13 && STRNICMP(pat, "", 13) == 0) + // "" + buflocal_nr = autocmd_bufnr; + else if (skipdigits(pat + 8) == pat + patlen - 1) + // "" + buflocal_nr = atoi((char *)pat + 8); + } + } + + if (is_buflocal) + { + // normalize pat into standard "#N" form + sprintf((char *)buflocal_pat, "", buflocal_nr); + pat = buflocal_pat; // can modify pat and patlen + patlen = (int)STRLEN(buflocal_pat); // but not endpat + } + + /* + * Find AutoPat entries with this pattern. When adding a command it + * always goes at or after the last one, so start at the end. + */ + if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL) + prev_ap = &last_autopat[(int)event]; + else + prev_ap = &first_autopat[(int)event]; + while ((ap = *prev_ap) != NULL) + { + if (ap->pat != NULL) + { + /* + * Accept a pattern when: + * - a group was specified and it's that group, or a group was + * not specified and it's the current group, or a group was + * not specified and we are listing + * - the length of the pattern matches + * - the pattern matches. + * For , this condition works because we normalize + * all buffer-local patterns. + */ + if ((allgroups || ap->group == findgroup) + && ap->patlen == patlen + && STRNCMP(pat, ap->pat, patlen) == 0) + { + /* + * Remove existing autocommands. + * If adding any new autocmd's for this AutoPat, don't + * delete the pattern from the autopat list, append to + * this list. + */ + if (forceit) + { + if (*cmd != NUL && ap->next == NULL) + { + au_remove_cmds(ap); + break; + } + au_remove_pat(ap); + } + + /* + * Show autocmd's for this autopat, or buflocals + */ + else if (*cmd == NUL) + show_autocmd(ap, event); + + /* + * Add autocmd to this autopat, if it's the last one. + */ + else if (ap->next == NULL) + break; + } + } + prev_ap = &ap->next; + } + + /* + * Add a new command. + */ + if (*cmd != NUL) + { + /* + * If the pattern we want to add a command to does appear at the + * end of the list (or not is not in the list at all), add the + * pattern at the end of the list. + */ + if (ap == NULL) + { + // refuse to add buffer-local ap if buffer number is invalid + if (is_buflocal && (buflocal_nr == 0 + || buflist_findnr(buflocal_nr) == NULL)) + { + semsg(_(e_buffer_nr_invalid_buffer_number), buflocal_nr); + return FAIL; + } + + ap = ALLOC_ONE(AutoPat); + if (ap == NULL) + return FAIL; + ap->pat = vim_strnsave(pat, patlen); + ap->patlen = patlen; + if (ap->pat == NULL) + { + vim_free(ap); + return FAIL; + } + +#ifdef FEAT_EVAL + // need to initialize last_mode for the first ModeChanged + // autocmd + if (event == EVENT_MODECHANGED && !has_modechanged()) + get_mode(last_mode); +#endif + // Initialize the fields checked by the WinScrolled and + // WinResized trigger to prevent them from firing right after + // the first autocmd is defined. + if ((event == EVENT_WINSCROLLED || event == EVENT_WINRESIZED) + && !(has_winscrolled() || has_winresized())) + { + tabpage_T *save_curtab = curtab; + tabpage_T *tp; + FOR_ALL_TABPAGES(tp) + { + unuse_tabpage(curtab); + use_tabpage(tp); + snapshot_windows_scroll_size(); + } + unuse_tabpage(curtab); + use_tabpage(save_curtab); + } + + if (is_buflocal) + { + ap->buflocal_nr = buflocal_nr; + ap->reg_prog = NULL; + } + else + { + char_u *reg_pat; + + ap->buflocal_nr = 0; + reg_pat = file_pat_to_reg_pat(pat, endpat, + &ap->allow_dirs, TRUE); + if (reg_pat != NULL) + ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC); + vim_free(reg_pat); + if (reg_pat == NULL || ap->reg_prog == NULL) + { + vim_free(ap->pat); + vim_free(ap); + return FAIL; + } + } + ap->cmds = NULL; + *prev_ap = ap; + last_autopat[(int)event] = ap; + ap->next = NULL; + if (group == AUGROUP_ALL) + ap->group = current_augroup; + else + ap->group = group; + } + + /* + * Add the autocmd at the end of the AutoCmd list. + */ + prev_ac = &(ap->cmds); + while ((ac = *prev_ac) != NULL) + prev_ac = &ac->next; + ac = ALLOC_ONE(AutoCmd); + if (ac == NULL) + return FAIL; + ac->cmd = vim_strsave(cmd); + ac->script_ctx = current_sctx; + if (flags & UC_VIM9) + ac->script_ctx.sc_version = SCRIPT_VERSION_VIM9; +#ifdef FEAT_EVAL + ac->script_ctx.sc_lnum += SOURCING_LNUM; +#endif + if (ac->cmd == NULL) + { + vim_free(ac); + return FAIL; + } + ac->next = NULL; + *prev_ac = ac; + ac->once = once; + ac->nested = nested; + } + } + + au_cleanup(); // may really delete removed patterns/commands now + return OK; +} + +/* + * Implementation of ":doautocmd [group] event [fname]". + * Return OK for success, FAIL for failure; + */ + int +do_doautocmd( + char_u *arg_start, + int do_msg, // give message for no matching autocmds? + int *did_something) +{ + char_u *arg = arg_start; + char_u *fname; + int nothing_done = TRUE; + int group; + + if (did_something != NULL) + *did_something = FALSE; + + /* + * Check for a legal group name. If not, use AUGROUP_ALL. + */ + group = au_get_grouparg(&arg); + if (arg == NULL) // out of memory + return FAIL; + + if (*arg == '*') + { + emsg(_(e_cant_execute_autocommands_for_all_events)); + return FAIL; + } + + /* + * Scan over the events. + * If we find an illegal name, return here, don't do anything. + */ + fname = find_end_event(arg, group != AUGROUP_ALL); + if (fname == NULL) + return FAIL; + + fname = skipwhite(fname); + + /* + * Loop over the events. + */ + while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg)) + if (apply_autocmds_group(event_name2nr(arg, &arg), + fname, NULL, TRUE, group, curbuf, NULL)) + nothing_done = FALSE; + + if (nothing_done && do_msg +#ifdef FEAT_EVAL + && !aborting() +#endif + ) + smsg(_("No matching autocommands: %s"), arg_start); + if (did_something != NULL) + *did_something = !nothing_done; + +#ifdef FEAT_EVAL + return aborting() ? FAIL : OK; +#else + return OK; +#endif +} + +/* + * ":doautoall": execute autocommands for each loaded buffer. + */ + void +ex_doautoall(exarg_T *eap) +{ + int retval = OK; + aco_save_T aco; + buf_T *buf; + bufref_T bufref; + char_u *arg = eap->arg; + int call_do_modelines = check_nomodeline(&arg); + int did_aucmd; + + /* + * This is a bit tricky: For some commands curwin->w_buffer needs to be + * equal to curbuf, but for some buffers there may not be a window. + * So we change the buffer for the current window for a moment. This + * gives problems when the autocommands make changes to the list of + * buffers or windows... + */ + FOR_ALL_BUFFERS(buf) + { + // Only do loaded buffers and skip the current buffer, it's done last. + if (buf->b_ml.ml_mfp == NULL || buf == curbuf) + continue; + + // Find a window for this buffer and save some values. + aucmd_prepbuf(&aco, buf); + if (curbuf != buf) + { + // Failed to find a window for this buffer. Better not execute + // autocommands then. + retval = FAIL; + break; + } + + set_bufref(&bufref, buf); + + // execute the autocommands for this buffer + retval = do_doautocmd(arg, FALSE, &did_aucmd); + + if (call_do_modelines && did_aucmd) + // Execute the modeline settings, but don't set window-local + // options if we are using the current window for another + // buffer. + do_modelines(is_aucmd_win(curwin) ? OPT_NOWIN : 0); + + // restore the current window + aucmd_restbuf(&aco); + + // stop if there is some error or buffer was deleted + if (retval == FAIL || !bufref_valid(&bufref)) + { + retval = FAIL; + break; + } + } + + // Execute autocommands for the current buffer last. + if (retval == OK) + { + do_doautocmd(arg, FALSE, &did_aucmd); + if (call_do_modelines && did_aucmd) + do_modelines(0); + } +} + +/* + * Check *argp for . When it is present return FALSE, otherwise + * return TRUE and advance *argp to after it. + * Thus return TRUE when do_modelines() should be called. + */ + int +check_nomodeline(char_u **argp) +{ + if (STRNCMP(*argp, "", 12) == 0) + { + *argp = skipwhite(*argp + 12); + return FALSE; + } + return TRUE; +} + +/* + * Prepare for executing autocommands for (hidden) buffer "buf". + * Search for a visible window containing the current buffer. If there isn't + * one then use an entry in "aucmd_win[]". + * Set "curbuf" and "curwin" to match "buf". + * When this fails "curbuf" is not equal "buf". + */ + void +aucmd_prepbuf( + aco_save_T *aco, // structure to save values in + buf_T *buf) // new curbuf +{ + win_T *win; + int save_ea; +#ifdef FEAT_AUTOCHDIR + int save_acd; +#endif + + // Find a window that is for the new buffer + if (buf == curbuf) // be quick when buf is curbuf + win = curwin; + else + FOR_ALL_WINDOWS(win) + if (win->w_buffer == buf) + break; + + // Allocate a window when needed. + win_T *auc_win = NULL; + int auc_idx = AUCMD_WIN_COUNT; + if (win == NULL) + { + for (auc_idx = 0; auc_idx < AUCMD_WIN_COUNT; ++auc_idx) + if (!aucmd_win[auc_idx].auc_win_used) + { + if (aucmd_win[auc_idx].auc_win == NULL) + aucmd_win[auc_idx].auc_win = win_alloc_popup_win(); + auc_win = aucmd_win[auc_idx].auc_win; + if (auc_win != NULL) + aucmd_win[auc_idx].auc_win_used = TRUE; + break; + } + + // If this fails (out of memory or using all AUCMD_WIN_COUNT + // entries) then we can't reliable execute the autocmd, return with + // "curbuf" unequal "buf". + if (auc_win == NULL) + return; + } + + aco->save_curwin_id = curwin->w_id; + aco->save_curbuf = curbuf; + aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id; + if (win != NULL) + { + // There is a window for "buf" in the current tab page, make it the + // curwin. This is preferred, it has the least side effects (esp. if + // "buf" is curbuf). + aco->use_aucmd_win_idx = -1; + curwin = win; + } + else + { + // There is no window for "buf", use "auc_win". To minimize the side + // effects, insert it in the current tab page. + // Anything related to a window (e.g., setting folds) may have + // unexpected results. + aco->use_aucmd_win_idx = auc_idx; + + win_init_popup_win(auc_win, buf); + + aco->globaldir = globaldir; + globaldir = NULL; + + // Split the current window, put the auc_win in the upper half. + // We don't want the BufEnter or WinEnter autocommands. + block_autocmds(); + make_snapshot(SNAP_AUCMD_IDX); + save_ea = p_ea; + p_ea = FALSE; + +#ifdef FEAT_AUTOCHDIR + // Prevent chdir() call in win_enter_ext(), through do_autochdir(). + save_acd = p_acd; + p_acd = FALSE; +#endif + + // no redrawing and don't set the window title + ++RedrawingDisabled; + (void)win_split_ins(0, WSP_TOP, auc_win, 0); + --RedrawingDisabled; + (void)win_comp_pos(); // recompute window positions + p_ea = save_ea; +#ifdef FEAT_AUTOCHDIR + p_acd = save_acd; +#endif + unblock_autocmds(); + curwin = auc_win; + } + curbuf = buf; + aco->new_curwin_id = curwin->w_id; + set_bufref(&aco->new_curbuf, curbuf); + + // disable the Visual area, the position may be invalid in another buffer + aco->save_VIsual_active = VIsual_active; + VIsual_active = FALSE; +} + +/* + * Cleanup after executing autocommands for a (hidden) buffer. + * Restore the window as it was (if possible). + */ + void +aucmd_restbuf( + aco_save_T *aco) // structure holding saved values +{ + int dummy; + win_T *save_curwin; + + if (aco->use_aucmd_win_idx >= 0) + { + win_T *awp = aucmd_win[aco->use_aucmd_win_idx].auc_win; + + --curbuf->b_nwindows; + // Find "awp", it can't be closed, but it may be in another tab + // page. Do not trigger autocommands here. + block_autocmds(); + if (curwin != awp) + { + tabpage_T *tp; + win_T *wp; + + FOR_ALL_TAB_WINDOWS(tp, wp) + { + if (wp == awp) + { + if (tp != curtab) + goto_tabpage_tp(tp, TRUE, TRUE); + win_goto(awp); + goto win_found; + } + } + } +win_found: + + // Remove the window and frame from the tree of frames. + (void)winframe_remove(curwin, &dummy, NULL); + win_remove(curwin, NULL); + + // The window is marked as not used, but it is not freed, it can be + // used again. + aucmd_win[aco->use_aucmd_win_idx].auc_win_used = FALSE; + last_status(FALSE); // may need to remove last status line + + if (!valid_tabpage_win(curtab)) + // no valid window in current tabpage + close_tabpage(curtab); + + restore_snapshot(SNAP_AUCMD_IDX, FALSE); + (void)win_comp_pos(); // recompute window positions + unblock_autocmds(); + + save_curwin = win_find_by_id(aco->save_curwin_id); + if (save_curwin != NULL) + curwin = save_curwin; + else + // Hmm, original window disappeared. Just use the first one. + curwin = firstwin; + curbuf = curwin->w_buffer; +#ifdef FEAT_JOB_CHANNEL + // May need to restore insert mode for a prompt buffer. + entering_window(curwin); +#endif + prevwin = win_find_by_id(aco->save_prevwin_id); +#ifdef FEAT_EVAL + vars_clear(&awp->w_vars->dv_hashtab); // free all w: variables + hash_init(&awp->w_vars->dv_hashtab); // re-use the hashtab +#endif + vim_free(globaldir); + globaldir = aco->globaldir; + + // the buffer contents may have changed + VIsual_active = aco->save_VIsual_active; + check_cursor(); + if (curwin->w_topline > curbuf->b_ml.ml_line_count) + { + curwin->w_topline = curbuf->b_ml.ml_line_count; +#ifdef FEAT_DIFF + curwin->w_topfill = 0; +#endif + } +#if defined(FEAT_GUI) + if (gui.in_use) + { + // Hide the scrollbars from the "awp" and update. + gui_mch_enable_scrollbar(&awp->w_scrollbars[SBAR_LEFT], FALSE); + gui_mch_enable_scrollbar(&awp->w_scrollbars[SBAR_RIGHT], FALSE); + gui_may_update_scrollbars(); + } +#endif + } + else + { + // Restore curwin. Use the window ID, a window may have been closed + // and the memory re-used for another one. + save_curwin = win_find_by_id(aco->save_curwin_id); + if (save_curwin != NULL) + { + // Restore the buffer which was previously edited by curwin, if + // it was changed, we are still the same window and the buffer is + // valid. + if (curwin->w_id == aco->new_curwin_id + && curbuf != aco->new_curbuf.br_buf + && bufref_valid(&aco->new_curbuf) + && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL) + { +# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL) + if (curwin->w_s == &curbuf->b_s) + curwin->w_s = &aco->new_curbuf.br_buf->b_s; +# endif + --curbuf->b_nwindows; + curbuf = aco->new_curbuf.br_buf; + curwin->w_buffer = curbuf; + ++curbuf->b_nwindows; + } + + curwin = save_curwin; + curbuf = curwin->w_buffer; + prevwin = win_find_by_id(aco->save_prevwin_id); + + // In case the autocommand moves the cursor to a position that + // does not exist in curbuf. + VIsual_active = aco->save_VIsual_active; + check_cursor(); + } + } + + VIsual_active = aco->save_VIsual_active; + check_cursor(); // just in case lines got deleted + if (VIsual_active) + check_pos(curbuf, &VIsual); +} + +static int autocmd_nested = FALSE; + +/* + * Execute autocommands for "event" and file name "fname". + * Return TRUE if some commands were executed. + */ + int +apply_autocmds( + event_T event, + char_u *fname, // NULL or empty means use actual file name + char_u *fname_io, // fname to use for on cmdline + int force, // when TRUE, ignore autocmd_busy + buf_T *buf) // buffer for +{ + return apply_autocmds_group(event, fname, fname_io, force, + AUGROUP_ALL, buf, NULL); +} + +/* + * Like apply_autocmds(), but with extra "eap" argument. This takes care of + * setting v:filearg. + */ + int +apply_autocmds_exarg( + event_T event, + char_u *fname, + char_u *fname_io, + int force, + buf_T *buf, + exarg_T *eap) +{ + return apply_autocmds_group(event, fname, fname_io, force, + AUGROUP_ALL, buf, eap); +} + +/* + * Like apply_autocmds(), but handles the caller's retval. If the script + * processing is being aborted or if retval is FAIL when inside a try + * conditional, no autocommands are executed. If otherwise the autocommands + * cause the script to be aborted, retval is set to FAIL. + */ + int +apply_autocmds_retval( + event_T event, + char_u *fname, // NULL or empty means use actual file name + char_u *fname_io, // fname to use for on cmdline + int force, // when TRUE, ignore autocmd_busy + buf_T *buf, // buffer for + int *retval) // pointer to caller's retval +{ + int did_cmd; + +#ifdef FEAT_EVAL + if (should_abort(*retval)) + return FALSE; +#endif + + did_cmd = apply_autocmds_group(event, fname, fname_io, force, + AUGROUP_ALL, buf, NULL); + if (did_cmd +#ifdef FEAT_EVAL + && aborting() +#endif + ) + *retval = FAIL; + return did_cmd; +} + +/* + * Return TRUE when there is a CursorHold autocommand defined. + */ + static int +has_cursorhold(void) +{ + return (first_autopat[(int)(get_real_state() == MODE_NORMAL_BUSY + ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL); +} + +/* + * Return TRUE if the CursorHold event can be triggered. + */ + int +trigger_cursorhold(void) +{ + int state; + + if (!did_cursorhold + && has_cursorhold() + && reg_recording == 0 + && typebuf.tb_len == 0 + && !ins_compl_active()) + { + state = get_real_state(); + if (state == MODE_NORMAL_BUSY || (state & MODE_INSERT) != 0) + return TRUE; + } + return FALSE; +} + +/* + * Return TRUE when there is a WinResized autocommand defined. + */ + int +has_winresized(void) +{ + return (first_autopat[(int)EVENT_WINRESIZED] != NULL); +} + +/* + * Return TRUE when there is a WinScrolled autocommand defined. + */ + int +has_winscrolled(void) +{ + return (first_autopat[(int)EVENT_WINSCROLLED] != NULL); +} + +/* + * Return TRUE when there is a CursorMoved autocommand defined. + */ + int +has_cursormoved(void) +{ + return (first_autopat[(int)EVENT_CURSORMOVED] != NULL); +} + +/* + * Return TRUE when there is a CursorMovedI autocommand defined. + */ + int +has_cursormovedI(void) +{ + return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL); +} + +/* + * Return TRUE when there is a TextChanged autocommand defined. + */ + int +has_textchanged(void) +{ + return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL); +} + +/* + * Return TRUE when there is a TextChangedI autocommand defined. + */ + int +has_textchangedI(void) +{ + return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL); +} + +/* + * Return TRUE when there is a TextChangedP autocommand defined. + */ + int +has_textchangedP(void) +{ + return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL); +} + +/* + * Return TRUE when there is an InsertCharPre autocommand defined. + */ + int +has_insertcharpre(void) +{ + return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL); +} + +/* + * Return TRUE when there is an CmdUndefined autocommand defined. + */ + int +has_cmdundefined(void) +{ + return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL); +} + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Return TRUE when there is a TextYankPost autocommand defined. + */ + int +has_textyankpost(void) +{ + return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL); +} +#endif + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Return TRUE when there is a CompleteChanged autocommand defined. + */ + int +has_completechanged(void) +{ + return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL); +} +#endif + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Return TRUE when there is a ModeChanged autocommand defined. + */ + int +has_modechanged(void) +{ + return (first_autopat[(int)EVENT_MODECHANGED] != NULL); +} +#endif + +/* + * Execute autocommands for "event" and file name "fname". + * Return TRUE if some commands were executed. + */ + static int +apply_autocmds_group( + event_T event, + char_u *fname, // NULL or empty means use actual file name + char_u *fname_io, // fname to use for on cmdline, NULL means + // use fname + int force, // when TRUE, ignore autocmd_busy + int group, // group ID, or AUGROUP_ALL + buf_T *buf, // buffer for + exarg_T *eap UNUSED) // command arguments +{ + char_u *sfname = NULL; // short file name + char_u *tail; + int save_changed; + buf_T *old_curbuf; + int retval = FALSE; + char_u *save_autocmd_fname; + int save_autocmd_fname_full; + int save_autocmd_bufnr; + char_u *save_autocmd_match; + int save_autocmd_busy; + int save_autocmd_nested; + static int nesting = 0; + AutoPatCmd_T patcmd; + AutoPat *ap; + sctx_T save_current_sctx; +#ifdef FEAT_EVAL + funccal_entry_T funccal_entry; + char_u *save_cmdarg; + long save_cmdbang; +#endif + static int filechangeshell_busy = FALSE; +#ifdef FEAT_PROFILE + proftime_T wait_time; +#endif + int did_save_redobuff = FALSE; + save_redo_T save_redo; + int save_KeyTyped = KeyTyped; + int save_did_emsg; + ESTACK_CHECK_DECLARATION + + /* + * Quickly return if there are no autocommands for this event or + * autocommands are blocked. + */ + if (event == NUM_EVENTS || first_autopat[(int)event] == NULL + || autocmd_blocked > 0) + goto BYPASS_AU; + + /* + * When autocommands are busy, new autocommands are only executed when + * explicitly enabled with the "nested" flag. + */ + if (autocmd_busy && !(force || autocmd_nested)) + goto BYPASS_AU; + +#ifdef FEAT_EVAL + /* + * Quickly return when immediately aborting on error, or when an interrupt + * occurred or an exception was thrown but not caught. + */ + if (aborting()) + goto BYPASS_AU; +#endif + + /* + * FileChangedShell never nests, because it can create an endless loop. + */ + if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL + || event == EVENT_FILECHANGEDSHELLPOST)) + goto BYPASS_AU; + + /* + * Ignore events in 'eventignore'. + */ + if (event_ignored(event)) + goto BYPASS_AU; + + /* + * Allow nesting of autocommands, but restrict the depth, because it's + * possible to create an endless loop. + */ + if (nesting == 10) + { + emsg(_(e_autocommand_nesting_too_deep)); + goto BYPASS_AU; + } + + /* + * Check if these autocommands are disabled. Used when doing ":all" or + * ":ball". + */ + if ( (autocmd_no_enter + && (event == EVENT_WINENTER || event == EVENT_BUFENTER)) + || (autocmd_no_leave + && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE))) + goto BYPASS_AU; + + if (event == EVENT_CMDLINECHANGED) + ++aucmd_cmdline_changed_count; + + /* + * Save the autocmd_* variables and info about the current buffer. + */ + save_autocmd_fname = autocmd_fname; + save_autocmd_fname_full = autocmd_fname_full; + save_autocmd_bufnr = autocmd_bufnr; + save_autocmd_match = autocmd_match; + save_autocmd_busy = autocmd_busy; + save_autocmd_nested = autocmd_nested; + save_changed = curbuf->b_changed; + old_curbuf = curbuf; + + /* + * Set the file name to be used for . + * Make a copy to avoid that changing a buffer name or directory makes it + * invalid. + */ + if (fname_io == NULL) + { + if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE + || event == EVENT_OPTIONSET + || event == EVENT_MODECHANGED) + autocmd_fname = NULL; + else if (fname != NULL && !ends_excmd(*fname)) + autocmd_fname = fname; + else if (buf != NULL) + autocmd_fname = buf->b_ffname; + else + autocmd_fname = NULL; + } + else + autocmd_fname = fname_io; + if (autocmd_fname != NULL) + autocmd_fname = vim_strsave(autocmd_fname); + autocmd_fname_full = FALSE; // call FullName_save() later + + /* + * Set the buffer number to be used for . + */ + if (buf == NULL) + autocmd_bufnr = 0; + else + autocmd_bufnr = buf->b_fnum; + + /* + * When the file name is NULL or empty, use the file name of buffer "buf". + * Always use the full path of the file name to match with, in case + * "allow_dirs" is set. + */ + if (fname == NULL || *fname == NUL) + { + if (buf == NULL) + fname = NULL; + else + { +#ifdef FEAT_SYN_HL + if (event == EVENT_SYNTAX) + fname = buf->b_p_syn; + else +#endif + if (event == EVENT_FILETYPE) + fname = buf->b_p_ft; + else + { + if (buf->b_sfname != NULL) + sfname = vim_strsave(buf->b_sfname); + fname = buf->b_ffname; + } + } + if (fname == NULL) + fname = (char_u *)""; + fname = vim_strsave(fname); // make a copy, so we can change it + } + else + { + sfname = vim_strsave(fname); + // Don't try expanding FileType, Syntax, FuncUndefined, WindowID, + // ColorScheme, QuickFixCmd*, DirChanged and similar. + if (event == EVENT_FILETYPE + || event == EVENT_SYNTAX + || event == EVENT_CMDLINECHANGED + || event == EVENT_CMDLINEENTER + || event == EVENT_CMDLINELEAVE + || event == EVENT_CMDWINENTER + || event == EVENT_CMDWINLEAVE + || event == EVENT_CMDUNDEFINED + || event == EVENT_FUNCUNDEFINED + || event == EVENT_REMOTEREPLY + || event == EVENT_SPELLFILEMISSING + || event == EVENT_QUICKFIXCMDPRE + || event == EVENT_COLORSCHEME + || event == EVENT_COLORSCHEMEPRE + || event == EVENT_OPTIONSET + || event == EVENT_QUICKFIXCMDPOST + || event == EVENT_DIRCHANGED + || event == EVENT_DIRCHANGEDPRE + || event == EVENT_MODECHANGED + || event == EVENT_MENUPOPUP + || event == EVENT_USER + || event == EVENT_WINCLOSED + || event == EVENT_WINRESIZED + || event == EVENT_WINSCROLLED) + { + fname = vim_strsave(fname); + autocmd_fname_full = TRUE; // don't expand it later + } + else + fname = FullName_save(fname, FALSE); + } + if (fname == NULL) // out of memory + { + vim_free(sfname); + retval = FALSE; + goto BYPASS_AU; + } + +#ifdef BACKSLASH_IN_FILENAME + /* + * Replace all backslashes with forward slashes. This makes the + * autocommand patterns portable between Unix and MS-DOS. + */ + if (sfname != NULL) + forward_slash(sfname); + forward_slash(fname); +#endif + +#ifdef VMS + // remove version for correct match + if (sfname != NULL) + vms_remove_version(sfname); + vms_remove_version(fname); +#endif + + /* + * Set the name to be used for . + */ + autocmd_match = fname; + + + // Don't redraw while doing autocommands. + ++RedrawingDisabled; + + // name and lnum are filled in later + estack_push(ETYPE_AUCMD, NULL, 0); + ESTACK_CHECK_SETUP + + save_current_sctx = current_sctx; + +#ifdef FEAT_EVAL +# ifdef FEAT_PROFILE + if (do_profiling == PROF_YES) + prof_child_enter(&wait_time); // doesn't count for the caller itself +# endif + + // Don't use local function variables, if called from a function. + save_funccal(&funccal_entry); +#endif + + /* + * When starting to execute autocommands, save the search patterns. + */ + if (!autocmd_busy) + { + save_search_patterns(); + if (!ins_compl_active()) + { + saveRedobuff(&save_redo); + did_save_redobuff = TRUE; + } + did_filetype = keep_filetype; + } + + /* + * Note that we are applying autocmds. Some commands need to know. + */ + autocmd_busy = TRUE; + filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL); + ++nesting; // see matching decrement below + + // Remember that FileType was triggered. Used for did_filetype(). + if (event == EVENT_FILETYPE) + did_filetype = TRUE; + + tail = gettail(fname); + + // Find first autocommand that matches + CLEAR_FIELD(patcmd); + patcmd.curpat = first_autopat[(int)event]; + patcmd.group = group; + patcmd.fname = fname; + patcmd.sfname = sfname; + patcmd.tail = tail; + patcmd.event = event; + patcmd.arg_bufnr = autocmd_bufnr; + auto_next_pat(&patcmd, FALSE); + + // found one, start executing the autocommands + if (patcmd.curpat != NULL) + { + // add to active_apc_list + patcmd.next = active_apc_list; + active_apc_list = &patcmd; + +#ifdef FEAT_EVAL + // set v:cmdarg (only when there is a matching pattern) + save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG); + if (eap != NULL) + { + save_cmdarg = set_cmdarg(eap, NULL); + set_vim_var_nr(VV_CMDBANG, (long)eap->forceit); + } + else + save_cmdarg = NULL; // avoid gcc warning +#endif + retval = TRUE; + // mark the last pattern, to avoid an endless loop when more patterns + // are added when executing autocommands + for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next) + ap->last = FALSE; + ap->last = TRUE; + + // Make sure cursor and topline are valid. The first time the current + // values are saved, restored by reset_lnums(). When nested only the + // values are corrected when needed. + if (nesting == 1) + check_lnums(TRUE); + else + check_lnums_nested(TRUE); + + save_did_emsg = did_emsg; + + do_cmdline(NULL, getnextac, (void *)&patcmd, + DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); + + did_emsg += save_did_emsg; + + if (nesting == 1) + // restore cursor and topline, unless they were changed + reset_lnums(); + +#ifdef FEAT_EVAL + if (eap != NULL) + { + (void)set_cmdarg(NULL, save_cmdarg); + set_vim_var_nr(VV_CMDBANG, save_cmdbang); + } +#endif + // delete from active_apc_list + if (active_apc_list == &patcmd) // just in case + active_apc_list = patcmd.next; + } + + --RedrawingDisabled; + autocmd_busy = save_autocmd_busy; + filechangeshell_busy = FALSE; + autocmd_nested = save_autocmd_nested; + vim_free(SOURCING_NAME); + ESTACK_CHECK_NOW + estack_pop(); + vim_free(autocmd_fname); + autocmd_fname = save_autocmd_fname; + autocmd_fname_full = save_autocmd_fname_full; + autocmd_bufnr = save_autocmd_bufnr; + autocmd_match = save_autocmd_match; + current_sctx = save_current_sctx; +#ifdef FEAT_EVAL + restore_funccal(); +# ifdef FEAT_PROFILE + if (do_profiling == PROF_YES) + prof_child_exit(&wait_time); +# endif +#endif + KeyTyped = save_KeyTyped; + vim_free(fname); + vim_free(sfname); + --nesting; // see matching increment above + + /* + * When stopping to execute autocommands, restore the search patterns and + * the redo buffer. Free any buffers in the au_pending_free_buf list and + * free any windows in the au_pending_free_win list. + */ + if (!autocmd_busy) + { + restore_search_patterns(); + if (did_save_redobuff) + restoreRedobuff(&save_redo); + did_filetype = FALSE; + while (au_pending_free_buf != NULL) + { + buf_T *b = au_pending_free_buf->b_next; + + vim_free(au_pending_free_buf); + au_pending_free_buf = b; + } + while (au_pending_free_win != NULL) + { + win_T *w = au_pending_free_win->w_next; + + vim_free(au_pending_free_win); + au_pending_free_win = w; + } + } + + /* + * Some events don't set or reset the Changed flag. + * Check if still in the same buffer! + */ + if (curbuf == old_curbuf + && (event == EVENT_BUFREADPOST + || event == EVENT_BUFWRITEPOST + || event == EVENT_FILEAPPENDPOST + || event == EVENT_VIMLEAVE + || event == EVENT_VIMLEAVEPRE)) + { + if (curbuf->b_changed != save_changed) + need_maketitle = TRUE; + curbuf->b_changed = save_changed; + } + + au_cleanup(); // may really delete removed patterns/commands now + +BYPASS_AU: + // When wiping out a buffer make sure all its buffer-local autocommands + // are deleted. + if (event == EVENT_BUFWIPEOUT && buf != NULL) + aubuflocal_remove(buf); + + if (retval == OK && event == EVENT_FILETYPE) + au_did_filetype = TRUE; + + return retval; +} + +# ifdef FEAT_EVAL +static char_u *old_termresponse = NULL; +# endif + +/* + * Block triggering autocommands until unblock_autocmd() is called. + * Can be used recursively, so long as it's symmetric. + */ + void +block_autocmds(void) +{ +# ifdef FEAT_EVAL + // Remember the value of v:termresponse. + if (autocmd_blocked == 0) + old_termresponse = get_vim_var_str(VV_TERMRESPONSE); +# endif + ++autocmd_blocked; +} + + void +unblock_autocmds(void) +{ + --autocmd_blocked; + +# ifdef FEAT_EVAL + // When v:termresponse was set while autocommands were blocked, trigger + // the autocommands now. Esp. useful when executing a shell command + // during startup (vimdiff). + if (autocmd_blocked == 0 + && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse) + apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf); +# endif +} + + int +is_autocmd_blocked(void) +{ + return autocmd_blocked != 0; +} + +/* + * Find next autocommand pattern that matches. + */ + static void +auto_next_pat( + AutoPatCmd_T *apc, + int stop_at_last) // stop when 'last' flag is set +{ + AutoPat *ap; + AutoCmd *cp; + char_u *name; + char *s; + estack_T *entry; + char_u *namep; + + entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; + + // Clear the exestack entry for this ETYPE_AUCMD entry. + VIM_CLEAR(entry->es_name); + entry->es_info.aucmd = NULL; + + for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next) + { + apc->curpat = NULL; + + // Only use a pattern when it has not been removed, has commands and + // the group matches. For buffer-local autocommands only check the + // buffer number. + if (ap->pat != NULL && ap->cmds != NULL + && (apc->group == AUGROUP_ALL || apc->group == ap->group)) + { + // execution-condition + if (ap->buflocal_nr == 0 + ? (match_file_pat(NULL, &ap->reg_prog, apc->fname, + apc->sfname, apc->tail, ap->allow_dirs)) + : ap->buflocal_nr == apc->arg_bufnr) + { + name = event_nr2name(apc->event); + s = _("%s Autocommands for \"%s\""); + namep = alloc(STRLEN(s) + STRLEN(name) + ap->patlen + 1); + if (namep != NULL) + { + sprintf((char *)namep, s, (char *)name, (char *)ap->pat); + if (p_verbose >= 8) + { + verbose_enter(); + smsg(_("Executing %s"), namep); + verbose_leave(); + } + } + + // Update the exestack entry for this autocmd. + entry->es_name = namep; + entry->es_info.aucmd = apc; + + apc->curpat = ap; + apc->nextcmd = ap->cmds; + // mark last command + for (cp = ap->cmds; cp->next != NULL; cp = cp->next) + cp->last = FALSE; + cp->last = TRUE; + } + line_breakcheck(); + if (apc->curpat != NULL) // found a match + break; + } + if (stop_at_last && ap->last) + break; + } +} + +/* + * Get the script context where autocommand "acp" is defined. + */ + sctx_T * +acp_script_ctx(AutoPatCmd_T *acp) +{ + return &acp->script_ctx; +} + +/* + * Get next autocommand command. + * Called by do_cmdline() to get the next line for ":if". + * Returns allocated string, or NULL for end of autocommands. + */ + char_u * +getnextac( + int c UNUSED, + void *cookie, + int indent UNUSED, + getline_opt_T options UNUSED) +{ + AutoPatCmd_T *acp = (AutoPatCmd_T *)cookie; + char_u *retval; + AutoCmd *ac; + + // Can be called again after returning the last line. + if (acp->curpat == NULL) + return NULL; + + // repeat until we find an autocommand to execute + for (;;) + { + // skip removed commands + while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL) + if (acp->nextcmd->last) + acp->nextcmd = NULL; + else + acp->nextcmd = acp->nextcmd->next; + + if (acp->nextcmd != NULL) + break; + + // at end of commands, find next pattern that matches + if (acp->curpat->last) + acp->curpat = NULL; + else + acp->curpat = acp->curpat->next; + if (acp->curpat != NULL) + auto_next_pat(acp, TRUE); + if (acp->curpat == NULL) + return NULL; + } + + ac = acp->nextcmd; + + if (p_verbose >= 9) + { + verbose_enter_scroll(); + smsg(_("autocommand %s"), ac->cmd); + msg_puts("\n"); // don't overwrite this either + verbose_leave_scroll(); + } + retval = vim_strsave(ac->cmd); + // Remove one-shot ("once") autocmd in anticipation of its execution. + if (ac->once) + au_del_cmd(ac); + autocmd_nested = ac->nested; + current_sctx = ac->script_ctx; + acp->script_ctx = current_sctx; + if (ac->last) + acp->nextcmd = NULL; + else + acp->nextcmd = ac->next; + return retval; +} + +/* + * Return TRUE if there is a matching autocommand for "fname". + * To account for buffer-local autocommands, function needs to know + * in which buffer the file will be opened. + */ + int +has_autocmd(event_T event, char_u *sfname, buf_T *buf) +{ + AutoPat *ap; + char_u *fname; + char_u *tail = gettail(sfname); + int retval = FALSE; + + fname = FullName_save(sfname, FALSE); + if (fname == NULL) + return FALSE; + +#ifdef BACKSLASH_IN_FILENAME + /* + * Replace all backslashes with forward slashes. This makes the + * autocommand patterns portable between Unix and MS-DOS. + */ + sfname = vim_strsave(sfname); + if (sfname != NULL) + forward_slash(sfname); + forward_slash(fname); +#endif + + FOR_ALL_AUTOCMD_PATTERNS(event, ap) + if (ap->pat != NULL && ap->cmds != NULL + && (ap->buflocal_nr == 0 + ? match_file_pat(NULL, &ap->reg_prog, + fname, sfname, tail, ap->allow_dirs) + : buf != NULL && ap->buflocal_nr == buf->b_fnum + )) + { + retval = TRUE; + break; + } + + vim_free(fname); +#ifdef BACKSLASH_IN_FILENAME + vim_free(sfname); +#endif + + return retval; +} + +/* + * Function given to ExpandGeneric() to obtain the list of autocommand group + * names. + */ + char_u * +get_augroup_name(expand_T *xp UNUSED, int idx) +{ + if (idx == augroups.ga_len) // add "END" add the end + return (char_u *)"END"; + if (idx < 0 || idx >= augroups.ga_len) // end of list + return NULL; + if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup()) + // skip deleted entries + return (char_u *)""; + return AUGROUP_NAME(idx); // return a name +} + +static int include_groups = FALSE; + + char_u * +set_context_in_autocmd( + expand_T *xp, + char_u *arg, + int doautocmd) // TRUE for :doauto*, FALSE for :autocmd +{ + char_u *p; + int group; + + // check for a group name, skip it if present + include_groups = FALSE; + p = arg; + group = au_get_grouparg(&arg); + if (group == AUGROUP_ERROR) + return NULL; + // If there only is a group name that's what we expand. + if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1])) + { + arg = p; + group = AUGROUP_ALL; + } + + // skip over event name + for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p) + if (*p == ',') + arg = p + 1; + if (*p == NUL) + { + if (group == AUGROUP_ALL) + include_groups = TRUE; + xp->xp_context = EXPAND_EVENTS; // expand event name + xp->xp_pattern = arg; + return NULL; + } + + // skip over pattern + arg = skipwhite(p); + while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\')) + arg++; + if (*arg) + return arg; // expand (next) command + + if (doautocmd) + xp->xp_context = EXPAND_FILES; // expand file names + else + xp->xp_context = EXPAND_NOTHING; // pattern is not expanded + return NULL; +} + +/* + * Function given to ExpandGeneric() to obtain the list of event names. + */ + char_u * +get_event_name(expand_T *xp UNUSED, int idx) +{ + if (idx < augroups.ga_len) // First list group names, if wanted + { + if (!include_groups || AUGROUP_NAME(idx) == NULL + || AUGROUP_NAME(idx) == get_deleted_augroup()) + return (char_u *)""; // skip deleted entries + return AUGROUP_NAME(idx); // return a name + } + return (char_u *)event_names[idx - augroups.ga_len].name; +} + + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Return TRUE if autocmd is supported. + */ + int +autocmd_supported(char_u *name) +{ + char_u *p; + + return (event_name2nr(name, &p) != NUM_EVENTS); +} + +/* + * Return TRUE if an autocommand is defined for a group, event and + * pattern: The group can be omitted to accept any group. "event" and "pattern" + * can be NULL to accept any event and pattern. "pattern" can be NULL to accept + * any pattern. Buffer-local patterns or are accepted. + * Used for: + * exists("#Group") or + * exists("#Group#Event") or + * exists("#Group#Event#pat") or + * exists("#Event") or + * exists("#Event#pat") + */ + int +au_exists(char_u *arg) +{ + char_u *arg_save; + char_u *pattern = NULL; + char_u *event_name; + char_u *p; + event_T event; + AutoPat *ap; + buf_T *buflocal_buf = NULL; + int group; + int retval = FALSE; + + // Make a copy so that we can change the '#' chars to a NUL. + arg_save = vim_strsave(arg); + if (arg_save == NULL) + return FALSE; + p = vim_strchr(arg_save, '#'); + if (p != NULL) + *p++ = NUL; + + // First, look for an autocmd group name + group = au_find_group(arg_save); + if (group == AUGROUP_ERROR) + { + // Didn't match a group name, assume the first argument is an event. + group = AUGROUP_ALL; + event_name = arg_save; + } + else + { + if (p == NULL) + { + // "Group": group name is present and it's recognized + retval = TRUE; + goto theend; + } + + // Must be "Group#Event" or "Group#Event#pat". + event_name = p; + p = vim_strchr(event_name, '#'); + if (p != NULL) + *p++ = NUL; // "Group#Event#pat" + } + + pattern = p; // "pattern" is NULL when there is no pattern + + // find the index (enum) for the event name + event = event_name2nr(event_name, &p); + + // return FALSE if the event name is not recognized + if (event == NUM_EVENTS) + goto theend; + + // Find the first autocommand for this event. + // If there isn't any, return FALSE; + // If there is one and no pattern given, return TRUE; + ap = first_autopat[(int)event]; + if (ap == NULL) + goto theend; + + // if pattern is "", special handling is needed which uses curbuf + // for pattern ", fnamecmp() will work fine + if (pattern != NULL && STRICMP(pattern, "") == 0) + buflocal_buf = curbuf; + + // Check if there is an autocommand with the given pattern. + for ( ; ap != NULL; ap = ap->next) + // only use a pattern when it has not been removed and has commands. + // For buffer-local autocommands, fnamecmp() works fine. + if (ap->pat != NULL && ap->cmds != NULL + && (group == AUGROUP_ALL || ap->group == group) + && (pattern == NULL + || (buflocal_buf == NULL + ? fnamecmp(ap->pat, pattern) == 0 + : ap->buflocal_nr == buflocal_buf->b_fnum))) + { + retval = TRUE; + break; + } + +theend: + vim_free(arg_save); + return retval; +} + +/* + * autocmd_add() and autocmd_delete() functions + */ + static void +autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete) +{ + list_T *aucmd_list; + listitem_T *li; + dict_T *event_dict; + dictitem_T *di; + char_u *event_name = NULL; + list_T *event_list; + listitem_T *eli; + event_T event; + char_u *group_name = NULL; + int group; + char_u *pat = NULL; + list_T *pat_list; + listitem_T *pli; + char_u *cmd = NULL; + char_u *end; + int once; + int nested; + int replace; // replace the cmd for a group/event + int retval = VVAL_TRUE; + int save_augroup = current_augroup; + + rettv->v_type = VAR_BOOL; + rettv->vval.v_number = VVAL_FALSE; + + if (check_for_list_arg(argvars, 0) == FAIL) + return; + + aucmd_list = argvars[0].vval.v_list; + if (aucmd_list == NULL) + return; + + FOR_ALL_LIST_ITEMS(aucmd_list, li) + { + VIM_CLEAR(group_name); + VIM_CLEAR(cmd); + event_name = NULL; + event_list = NULL; + pat = NULL; + pat_list = NULL; + + if (li->li_tv.v_type != VAR_DICT) + continue; + + event_dict = li->li_tv.vval.v_dict; + if (event_dict == NULL) + continue; + + di = dict_find(event_dict, (char_u *)"event", -1); + if (di != NULL) + { + if (di->di_tv.v_type == VAR_STRING) + { + event_name = di->di_tv.vval.v_string; + if (event_name == NULL) + { + emsg(_(e_string_required)); + continue; + } + } + else if (di->di_tv.v_type == VAR_LIST) + { + event_list = di->di_tv.vval.v_list; + if (event_list == NULL) + { + emsg(_(e_list_required)); + continue; + } + } + else + { + emsg(_(e_string_or_list_expected)); + continue; + } + } + + group_name = dict_get_string(event_dict, "group", TRUE); + if (group_name == NULL || *group_name == NUL) + // if the autocmd group name is not specified, then use the current + // autocmd group + group = current_augroup; + else + { + group = au_find_group(group_name); + if (group == AUGROUP_ERROR) + { + if (delete) + { + semsg(_(e_no_such_group_str), group_name); + retval = VVAL_FALSE; + break; + } + // group is not found, create it now + group = au_new_group(group_name); + if (group == AUGROUP_ERROR) + { + semsg(_(e_no_such_group_str), group_name); + retval = VVAL_FALSE; + break; + } + + current_augroup = group; + } + } + + // if a buffer number is specified, then generate a pattern of the form + // ". Otherwise, use the pattern supplied by the user. + if (dict_has_key(event_dict, "bufnr")) + { + varnumber_T bnum; + + bnum = dict_get_number_def(event_dict, "bufnr", -1); + if (bnum == -1) + continue; + + vim_snprintf((char *)IObuff, IOSIZE, "", (int)bnum); + pat = IObuff; + } + else + { + di = dict_find(event_dict, (char_u *)"pattern", -1); + if (di != NULL) + { + if (di->di_tv.v_type == VAR_STRING) + { + pat = di->di_tv.vval.v_string; + if (pat == NULL) + { + emsg(_(e_string_required)); + continue; + } + } + else if (di->di_tv.v_type == VAR_LIST) + { + pat_list = di->di_tv.vval.v_list; + if (pat_list == NULL) + { + emsg(_(e_list_required)); + continue; + } + } + else + { + emsg(_(e_string_or_list_expected)); + continue; + } + } + else if (delete) + pat = (char_u *)""; + } + + once = dict_get_bool(event_dict, "once", FALSE); + nested = dict_get_bool(event_dict, "nested", FALSE); + // if 'replace' is true, then remove all the commands associated with + // this autocmd event/group and add the new command. + replace = dict_get_bool(event_dict, "replace", FALSE); + + cmd = dict_get_string(event_dict, "cmd", TRUE); + if (cmd == NULL) + { + if (delete) + cmd = vim_strsave((char_u *)""); + else + continue; + } + + if (delete && (event_name == NULL + || (event_name[0] == '*' && event_name[1] == NUL))) + { + // if the event name is not specified or '*', delete all the events + for (event = (event_T)0; (int)event < NUM_EVENTS; + event = (event_T)((int)event + 1)) + { + if (do_autocmd_event(event, pat, once, nested, cmd, delete, + group, 0) == FAIL) + { + retval = VVAL_FALSE; + break; + } + } + } + else + { + char_u *p = NULL; + + eli = NULL; + end = NULL; + while (TRUE) + { + if (event_list != NULL) + { + if (eli == NULL) + eli = event_list->lv_first; + else + eli = eli->li_next; + if (eli == NULL) + break; + if (eli->li_tv.v_type != VAR_STRING + || (p = eli->li_tv.vval.v_string) == NULL) + { + emsg(_(e_string_required)); + break; + } + } + else + { + if (p == NULL) + p = event_name; + if (p == NULL || *p == NUL) + break; + } + + event = event_name2nr(p, &end); + if (event == NUM_EVENTS || *end != NUL) + { + // this also catches something following a valid event name + semsg(_(e_no_such_event_str), p); + retval = VVAL_FALSE; + break; + } + if (pat != NULL) + { + if (do_autocmd_event(event, pat, once, nested, cmd, + delete | replace, group, 0) == FAIL) + { + retval = VVAL_FALSE; + break; + } + } + else if (pat_list != NULL) + { + FOR_ALL_LIST_ITEMS(pat_list, pli) + { + if (pli->li_tv.v_type != VAR_STRING + || pli->li_tv.vval.v_string == NULL) + { + emsg(_(e_string_required)); + continue; + } + if (do_autocmd_event(event, + pli->li_tv.vval.v_string, once, nested, + cmd, delete | replace, group, 0) == + FAIL) + { + retval = VVAL_FALSE; + break; + } + } + if (retval == VVAL_FALSE) + break; + } + if (event_name != NULL) + p = end; + } + } + + // if only the autocmd group name is specified for delete and the + // autocmd event, pattern and cmd are not specified, then delete the + // autocmd group. + if (delete && group_name != NULL && + (event_name == NULL || event_name[0] == NUL) + && (pat == NULL || pat[0] == NUL) + && (cmd == NULL || cmd[0] == NUL)) + au_del_group(group_name); + } + + VIM_CLEAR(group_name); + VIM_CLEAR(cmd); + + current_augroup = save_augroup; + rettv->vval.v_number = retval; +} + +/* + * autocmd_add() function + */ + void +f_autocmd_add(typval_T *argvars, typval_T *rettv) +{ + autocmd_add_or_delete(argvars, rettv, FALSE); +} + +/* + * autocmd_delete() function + */ + void +f_autocmd_delete(typval_T *argvars, typval_T *rettv) +{ + autocmd_add_or_delete(argvars, rettv, TRUE); +} + +/* + * autocmd_get() function + * Returns a List of autocmds. + */ + void +f_autocmd_get(typval_T *argvars, typval_T *rettv) +{ + event_T event_arg = NUM_EVENTS; + event_T event; + AutoPat *ap; + AutoCmd *ac; + list_T *event_list; + dict_T *event_dict; + char_u *event_name = NULL; + char_u *pat = NULL; + char_u *name = NULL; + int group = AUGROUP_ALL; + + if (rettv_list_alloc(rettv) == FAIL) + return; + if (check_for_opt_dict_arg(argvars, 0) == FAIL) + return; + + if (argvars[0].v_type == VAR_DICT) + { + // return only the autocmds in the specified group + if (dict_has_key(argvars[0].vval.v_dict, "group")) + { + name = dict_get_string(argvars[0].vval.v_dict, "group", TRUE); + if (name == NULL) + return; + + if (*name == NUL) + group = AUGROUP_DEFAULT; + else + { + group = au_find_group(name); + if (group == AUGROUP_ERROR) + { + semsg(_(e_no_such_group_str), name); + vim_free(name); + return; + } + } + vim_free(name); + } + + // return only the autocmds for the specified event + if (dict_has_key(argvars[0].vval.v_dict, "event")) + { + int i; + + name = dict_get_string(argvars[0].vval.v_dict, "event", TRUE); + if (name == NULL) + return; + + if (name[0] == '*' && name[1] == NUL) + event_arg = NUM_EVENTS; + else + { + for (i = 0; event_names[i].name != NULL; i++) + if (STRICMP(event_names[i].name, name) == 0) + break; + if (event_names[i].name == NULL) + { + semsg(_(e_no_such_event_str), name); + vim_free(name); + return; + } + event_arg = event_names[i].event; + } + vim_free(name); + } + + // return only the autocmds for the specified pattern + if (dict_has_key(argvars[0].vval.v_dict, "pattern")) + { + pat = dict_get_string(argvars[0].vval.v_dict, "pattern", TRUE); + if (pat == NULL) + return; + } + } + + event_list = rettv->vval.v_list; + + // iterate through all the autocmd events + for (event = (event_T)0; (int)event < NUM_EVENTS; + event = (event_T)((int)event + 1)) + { + if (event_arg != NUM_EVENTS && event != event_arg) + continue; + + event_name = event_nr2name(event); + + // iterate through all the patterns for this autocmd event + FOR_ALL_AUTOCMD_PATTERNS(event, ap) + { + char_u *group_name; + + if (group != AUGROUP_ALL && group != ap->group) + continue; + + if (pat != NULL && STRCMP(pat, ap->pat) != 0) + continue; + + group_name = get_augroup_name(NULL, ap->group); + + // iterate through all the commands for this pattern and add one + // item for each cmd. + for (ac = ap->cmds; ac != NULL; ac = ac->next) + { + event_dict = dict_alloc(); + if (event_dict == NULL + || list_append_dict(event_list, event_dict) == FAIL) + return; + + if (dict_add_string(event_dict, "event", event_name) == FAIL + || dict_add_string(event_dict, "group", + group_name == NULL ? (char_u *)"" + : group_name) == FAIL + || (ap->buflocal_nr != 0 + && (dict_add_number(event_dict, "bufnr", + ap->buflocal_nr) == FAIL)) + || dict_add_string(event_dict, "pattern", + ap->pat) == FAIL + || dict_add_string(event_dict, "cmd", ac->cmd) == FAIL + || dict_add_bool(event_dict, "once", ac->once) == FAIL + || dict_add_bool(event_dict, "nested", + ac->nested) == FAIL) + return; + } + } + } + + vim_free(pat); +} + +#endif diff --git a/src/beval.c b/src/beval.c new file mode 100644 index 0000000..375795e --- /dev/null +++ b/src/beval.c @@ -0,0 +1,356 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * Visual Workshop integration by Gordon Prieur + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +#include "vim.h" + +#if defined(FEAT_BEVAL) || defined(FEAT_PROP_POPUP) || defined(PROTO) +/* + * Find text under the mouse position "row" / "col". + * If "getword" is TRUE the returned text in "*textp" is not the whole line but + * the relevant word in allocated memory. + * Return OK if found. + * Return FAIL if not found, no text at the mouse position. + */ + int +find_word_under_cursor( + int mouserow, + int mousecol, + int getword, + int flags, // flags for find_ident_at_pos() + win_T **winp, // can be NULL + linenr_T *lnump, // can be NULL + char_u **textp, + int *colp, // column where mouse hovers, can be NULL + int *startcolp) // column where text starts, can be NULL +{ + int row = mouserow; + int col = mousecol; + int scol; + win_T *wp; + char_u *lbuf; + linenr_T lnum; + + *textp = NULL; + wp = mouse_find_win(&row, &col, FAIL_POPUP); + if (wp == NULL || row < 0 || row >= wp->w_height || col >= wp->w_width) + return FAIL; + + // Found a window and the cursor is in the text. Now find the line + // number. + if (mouse_comp_pos(wp, &row, &col, &lnum, NULL)) + return FAIL; // position is below the last line + + // Not past end of the file. + lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE); + if (col > win_linetabsize(wp, lnum, lbuf, (colnr_T)MAXCOL)) + return FAIL; // past end of line + + // Not past end of line. + if (getword) + { + // For Netbeans we get the relevant part of the line + // instead of the whole line. + int len; + pos_T *spos = NULL, *epos = NULL; + + if (VIsual_active) + { + if (LT_POS(VIsual, curwin->w_cursor)) + { + spos = &VIsual; + epos = &curwin->w_cursor; + } + else + { + spos = &curwin->w_cursor; + epos = &VIsual; + } + } + + col = vcol2col(wp, lnum, col); + scol = col; + + if (VIsual_active + && wp->w_buffer == curwin->w_buffer + && (lnum == spos->lnum + ? col >= (int)spos->col + : lnum > spos->lnum) + && (lnum == epos->lnum + ? col <= (int)epos->col + : lnum < epos->lnum)) + { + // Visual mode and pointing to the line with the + // Visual selection: return selected text, with a + // maximum of one line. + if (spos->lnum != epos->lnum || spos->col == epos->col) + return FAIL; + + lbuf = ml_get_buf(curwin->w_buffer, VIsual.lnum, FALSE); + len = epos->col - spos->col; + if (*p_sel != 'e') + len += mb_ptr2len(lbuf + epos->col); + lbuf = vim_strnsave(lbuf + spos->col, len); + lnum = spos->lnum; + col = spos->col; + scol = col; + } + else + { + // Find the word under the cursor. + ++emsg_off; + len = find_ident_at_pos(wp, lnum, (colnr_T)col, + &lbuf, &scol, flags); + --emsg_off; + if (len == 0) + return FAIL; + lbuf = vim_strnsave(lbuf, len); + } + } + else + scol = col; + + if (winp != NULL) + *winp = wp; + if (lnump != NULL) + *lnump = lnum; + *textp = lbuf; + if (colp != NULL) + *colp = col; + if (startcolp != NULL) + *startcolp = scol; + + return OK; +} +#endif + +#if defined(FEAT_BEVAL) || defined(PROTO) + +/* + * Get the text and position to be evaluated for "beval". + * If "getword" is TRUE the returned text is not the whole line but the + * relevant word in allocated memory. + * Returns OK or FAIL. + */ + int +get_beval_info( + BalloonEval *beval, + int getword, + win_T **winp, + linenr_T *lnump, + char_u **textp, + int *colp) +{ + int row = mouse_row; + int col = mouse_col; + +# ifdef FEAT_BEVAL_GUI + if (gui.in_use) + { + row = Y_2_ROW(beval->y); + col = X_2_COL(beval->x); + } +# endif + if (find_word_under_cursor(row, col, getword, + FIND_IDENT + FIND_STRING + FIND_EVAL, + winp, lnump, textp, colp, NULL) == OK) + { +# ifdef FEAT_VARTABS + vim_free(beval->vts); + beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array); + if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL) + { + if (getword) + vim_free(*textp); + return FAIL; + } +# endif + beval->ts = (*winp)->w_buffer->b_p_ts; + return OK; + } + + return FAIL; +} + +/* + * Show a balloon with "mesg" or "list". + * Hide the balloon when both are NULL. + */ + void +post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED) +{ +# ifdef FEAT_BEVAL_TERM +# ifdef FEAT_GUI + if (!gui.in_use) +# endif + ui_post_balloon(mesg, list); +# endif +# ifdef FEAT_BEVAL_GUI + if (gui.in_use) + // GUI can't handle a list + gui_mch_post_balloon(beval, mesg); +# endif +} + +/* + * Returns TRUE if the balloon eval has been enabled: + * 'ballooneval' for the GUI and 'balloonevalterm' for the terminal. + * Also checks if the screen isn't scrolled up. + */ + int +can_use_beval(void) +{ + return (0 +#ifdef FEAT_BEVAL_GUI + || (gui.in_use && p_beval) +#endif +#ifdef FEAT_BEVAL_TERM + || ( +# ifdef FEAT_GUI + !gui.in_use && +# endif + p_bevalterm) +#endif + ) && msg_scrolled == 0; +} + +# ifdef FEAT_EVAL +/* + * Evaluate the expression 'bexpr' and set the text in the balloon 'beval'. + */ + static void +bexpr_eval( + BalloonEval *beval, + char_u *bexpr, + win_T *wp, + linenr_T lnum, + int col, + char_u *text) +{ + win_T *cw; + long winnr = 0; + buf_T *save_curbuf; + int use_sandbox; + static char_u *result = NULL; + size_t len; + + sctx_T save_sctx = current_sctx; + + // Convert window pointer to number. + for (cw = firstwin; cw != wp; cw = cw->w_next) + ++winnr; + + set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum); + set_vim_var_nr(VV_BEVAL_WINNR, winnr); + set_vim_var_nr(VV_BEVAL_WINID, wp->w_id); + set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum); + set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1)); + set_vim_var_string(VV_BEVAL_TEXT, text, -1); + vim_free(text); + + /* + * Temporarily change the curbuf, so that we can determine whether + * the buffer-local balloonexpr option was set insecurely. + */ + save_curbuf = curbuf; + curbuf = wp->w_buffer; + use_sandbox = was_set_insecurely((char_u *)"balloonexpr", + *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL); + curbuf = save_curbuf; + if (use_sandbox) + ++sandbox; + ++textlock; + + if (bexpr == p_bexpr) + { + sctx_T *sp = get_option_sctx("balloonexpr"); + + if (sp != NULL) + current_sctx = *sp; + } + else + current_sctx = curbuf->b_p_script_ctx[BV_BEXPR]; + + vim_free(result); + result = eval_to_string(bexpr, TRUE, TRUE); + + // Remove one trailing newline, it is added when the result was a + // list and it's hardly ever useful. If the user really wants a + // trailing newline he can add two and one remains. + if (result != NULL) + { + len = STRLEN(result); + if (len > 0 && result[len - 1] == NL) + result[len - 1] = NUL; + } + + if (use_sandbox) + --sandbox; + --textlock; + current_sctx = save_sctx; + + set_vim_var_string(VV_BEVAL_TEXT, NULL, -1); + if (result != NULL && result[0] != NUL) + post_balloon(beval, result, NULL); + + // The 'balloonexpr' evaluation may show something on the screen + // that requires a screen update. + if (must_redraw) + redraw_after_callback(FALSE, FALSE); +} +# endif + +/* + * Common code, invoked when the mouse is resting for a moment. + */ + void +general_beval_cb(BalloonEval *beval, int state UNUSED) +{ +#ifdef FEAT_EVAL + win_T *wp; + int col; + linenr_T lnum; + char_u *text; + char_u *bexpr; +#endif + static int recursive = FALSE; + + // Don't do anything when 'ballooneval' is off, messages scrolled the + // windows up or we have no beval area. + if (!can_use_beval() || beval == NULL) + return; + + // Don't do this recursively. Happens when the expression evaluation + // takes a long time and invokes something that checks for CTRL-C typed. + if (recursive) + return; + recursive = TRUE; + +#ifdef FEAT_EVAL + if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK) + { + bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr + : wp->w_buffer->b_p_bexpr; + if (*bexpr != NUL) + { + bexpr_eval(beval, bexpr, wp, lnum, col, text); + recursive = FALSE; + return; + } + } +#endif +#ifdef FEAT_NETBEANS_INTG + if (bevalServers & BEVAL_NETBEANS) + netbeans_beval_cb(beval, state); +#endif + + recursive = FALSE; +} + +#endif diff --git a/src/beval.h b/src/beval.h new file mode 100644 index 0000000..4332389 --- /dev/null +++ b/src/beval.h @@ -0,0 +1,95 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * Visual Workshop integration by Gordon Prieur + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +#if !defined(BEVAL__H) && (defined(FEAT_BEVAL) || defined(PROTO)) +#define BEVAL__H + +#ifdef FEAT_GUI_GTK +# ifdef USE_GTK3 +# include +# else +# include +# endif +#else +# if defined(FEAT_GUI_X11) +# include +# endif +#endif + +typedef enum +{ + ShS_NEUTRAL, // nothing showing or pending + ShS_PENDING, // data requested from debugger + ShS_UPDATE_PENDING, // switching information displayed + ShS_SHOWING // the balloon is being displayed +} BeState; + +typedef struct BalloonEvalStruct +{ +#ifdef FEAT_BEVAL_GUI +# ifdef FEAT_GUI_GTK + GtkWidget *target; // widget we are monitoring + GtkWidget *balloonShell; + GtkWidget *balloonLabel; + unsigned int timerID; // timer for run + BeState showState; // tells us what's currently going on + int x; + int y; + unsigned int state; // Button/Modifier key state +# else +# if !defined(FEAT_GUI_MSWIN) + Widget target; // widget we are monitoring + Widget balloonShell; + Widget balloonLabel; + XtIntervalId timerID; // timer for run + BeState showState; // tells us what's currently going on + XtAppContext appContext; // used in event handler + Position x; + Position y; + Position x_root; + Position y_root; + int state; // Button/Modifier key state +# else + HWND target; + HWND balloon; + int x; + int y; + BeState showState; // tells us what's currently going on +# endif +# endif +# if !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MSWIN) + Dimension screen_width; // screen width in pixels + Dimension screen_height; // screen height in pixels +# endif + void (*msgCB)(struct BalloonEvalStruct *, int); + void *clientData; // For callback +#endif + + int ts; // tabstop setting for this buffer +#ifdef FEAT_VARTABS + int *vts; // vartabstop setting for this buffer +#endif + char_u *msg; // allocated: current text +#ifdef FEAT_GUI_MSWIN + void *tofree; +#endif +#ifdef FEAT_GUI_HAIKU + int x; + int y; +#endif +} BalloonEval; + +#define EVAL_OFFSET_X 15 // displacement of beval topleft corner from pointer +#define EVAL_OFFSET_Y 10 + +#ifdef FEAT_BEVAL_GUI +# include "gui_beval.pro" +#endif + +#endif // BEVAL__H and FEAT_BEVAL_GUI diff --git a/src/bigvim.bat b/src/bigvim.bat new file mode 100644 index 0000000..e82eabd --- /dev/null +++ b/src/bigvim.bat @@ -0,0 +1,5 @@ +:: command to build big Vim with OLE, Lua, Perl, Python, Racket, Ruby and Tcl +SET VCDIR="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\" +SET TOOLDIR=E:\ +%VCDIR%nmake -f Make_mvc.mak GUI=yes OLE=yes LUA=%TOOLDIR%lua53 DYNAMIC_LUA=yes LUA_VER=53 PERL=%TOOLDIR%perl524 DYNAMIC_PERL=yes PERL_VER=524 PYTHON=%TOOLDIR%python27 DYNAMIC_PYTHON=yes PYTHON_VER=27 PYTHON3=%TOOLDIR%python36 DYNAMIC_PYTHON3=yes PYTHON3_VER=36 MZSCHEME=%TOOLDIR%Racket DYNAMIC_MZSCHEME=yes MZSCHEME_VER=3m_a36fs8 RUBY=%TOOLDIR%ruby24 DYNAMIC_RUBY=yes RUBY_VER=24 RUBY_API_VER_LONG=2.4.0 RUBY_MSVCRT_NAME=msvcrt TCL=%TOOLDIR%ActiveTcl TCL_VER=86 TCL_VER_LONG=8.6 DYNAMIC_TCL=yes TCL_DLL=tcl86t.dll %1 IME=yes CSCOPE=yes DIRECTX=yes + diff --git a/src/bigvim64.bat b/src/bigvim64.bat new file mode 100644 index 0000000..8d5fba0 --- /dev/null +++ b/src/bigvim64.bat @@ -0,0 +1,7 @@ +:: command to build big Vim 64 bit with OLE, Perl and Python. +:: First run: %VCDIR%\vcvarsall.bat x86_amd64 +:: Ruby and Tcl are excluded, doesn't seem to work. +SET VCDIR="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\" +SET TOOLDIR=E:\ +%VCDIR%\bin\nmake -f Make_mvc.mak CPU=AMD64 GUI=yes OLE=yes PERL=E:\perl524 DYNAMIC_PERL=yes PERL_VER=524 PYTHON=%TOOLDIR%python27 DYNAMIC_PYTHON=yes PYTHON_VER=27 PYTHON3=%TOOLDIR%python35 DYNAMIC_PYTHON3=yes PYTHON3_VER=35 %1 IME=yes CSCOPE=yes + diff --git a/src/blob.c b/src/blob.c new file mode 100644 index 0000000..bfc7723 --- /dev/null +++ b/src/blob.c @@ -0,0 +1,853 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * blob.c: Blob support by Yasuhiro Matsumoto + */ + +#include "vim.h" + +#if defined(FEAT_EVAL) || defined(PROTO) + +/* + * Allocate an empty blob. + * Caller should take care of the reference count. + */ + blob_T * +blob_alloc(void) +{ + blob_T *blob = ALLOC_CLEAR_ONE_ID(blob_T, aid_blob_alloc); + + if (blob != NULL) + ga_init2(&blob->bv_ga, 1, 100); + return blob; +} + +/* + * Allocate an empty blob for a return value, with reference count set. + * Returns OK or FAIL. + */ + int +rettv_blob_alloc(typval_T *rettv) +{ + blob_T *b = blob_alloc(); + + if (b == NULL) + return FAIL; + + rettv_blob_set(rettv, b); + return OK; +} + +/* + * Set a blob as the return value. + */ + void +rettv_blob_set(typval_T *rettv, blob_T *b) +{ + rettv->v_type = VAR_BLOB; + rettv->vval.v_blob = b; + if (b != NULL) + ++b->bv_refcount; +} + + int +blob_copy(blob_T *from, typval_T *to) +{ + int len; + + to->v_type = VAR_BLOB; + to->v_lock = 0; + if (from == NULL) + { + to->vval.v_blob = NULL; + return OK; + } + + if (rettv_blob_alloc(to) == FAIL) + return FAIL; + + len = from->bv_ga.ga_len; + if (len > 0) + { + to->vval.v_blob->bv_ga.ga_data = + vim_memsave(from->bv_ga.ga_data, len); + if (to->vval.v_blob->bv_ga.ga_data == NULL) + len = 0; + } + to->vval.v_blob->bv_ga.ga_len = len; + to->vval.v_blob->bv_ga.ga_maxlen = len; + + return OK; +} + + void +blob_free(blob_T *b) +{ + ga_clear(&b->bv_ga); + vim_free(b); +} + +/* + * Unreference a blob: decrement the reference count and free it when it + * becomes zero. + */ + void +blob_unref(blob_T *b) +{ + if (b != NULL && --b->bv_refcount <= 0) + blob_free(b); +} + +/* + * Get the length of data. + */ + long +blob_len(blob_T *b) +{ + if (b == NULL) + return 0L; + return b->bv_ga.ga_len; +} + +/* + * Get byte "idx" in blob "b". + * Caller must check that "idx" is valid. + */ + int +blob_get(blob_T *b, int idx) +{ + return ((char_u*)b->bv_ga.ga_data)[idx]; +} + +/* + * Store one byte "byte" in blob "blob" at "idx". + * Caller must make sure that "idx" is valid. + */ + void +blob_set(blob_T *blob, int idx, int byte) +{ + ((char_u*)blob->bv_ga.ga_data)[idx] = byte; +} + +/* + * Store one byte "byte" in blob "blob" at "idx". + * Append one byte if needed. + */ + void +blob_set_append(blob_T *blob, int idx, int byte) +{ + garray_T *gap = &blob->bv_ga; + + // Allow for appending a byte. Setting a byte beyond + // the end is an error otherwise. + if (idx < gap->ga_len + || (idx == gap->ga_len && ga_grow(gap, 1) == OK)) + { + blob_set(blob, idx, byte); + if (idx == gap->ga_len) + ++gap->ga_len; + } +} + +/* + * Return TRUE when two blobs have exactly the same values. + */ + int +blob_equal( + blob_T *b1, + blob_T *b2) +{ + int i; + int len1 = blob_len(b1); + int len2 = blob_len(b2); + + // empty and NULL are considered the same + if (len1 == 0 && len2 == 0) + return TRUE; + if (b1 == b2) + return TRUE; + if (len1 != len2) + return FALSE; + + for (i = 0; i < b1->bv_ga.ga_len; i++) + if (blob_get(b1, i) != blob_get(b2, i)) return FALSE; + return TRUE; +} + +/* + * Read blob from file "fd". + * Caller has allocated a blob in "rettv". + * Return OK or FAIL. + */ + int +read_blob(FILE *fd, typval_T *rettv, off_T offset, off_T size_arg) +{ + blob_T *blob = rettv->vval.v_blob; + struct stat st; + int whence; + off_T size = size_arg; + + if (fstat(fileno(fd), &st) < 0) + return FAIL; // can't read the file, error + + if (offset >= 0) + { + // The size defaults to the whole file. If a size is given it is + // limited to not go past the end of the file. + if (size == -1 || (size > st.st_size - offset +#ifdef S_ISCHR + && !S_ISCHR(st.st_mode) +#endif + )) + // size may become negative, checked below + size = st.st_size - offset; + whence = SEEK_SET; + } + else + { + // limit the offset to not go before the start of the file + if (-offset > st.st_size +#ifdef S_ISCHR + && !S_ISCHR(st.st_mode) +#endif + ) + offset = -st.st_size; + // Size defaults to reading until the end of the file. + if (size == -1 || size > -offset) + size = -offset; + whence = SEEK_END; + } + if (size <= 0) + return OK; + if (offset != 0 && vim_fseek(fd, offset, whence) != 0) + return OK; + + if (ga_grow(&blob->bv_ga, (int)size) == FAIL) + return FAIL; + blob->bv_ga.ga_len = (int)size; + if (fread(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd) + < (size_t)blob->bv_ga.ga_len) + { + // An empty blob is returned on error. + blob_free(rettv->vval.v_blob); + rettv->vval.v_blob = NULL; + return FAIL; + } + return OK; +} + +/* + * Write "blob" to file "fd". + * Return OK or FAIL. + */ + int +write_blob(FILE *fd, blob_T *blob) +{ + if (fwrite(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd) + < (size_t)blob->bv_ga.ga_len) + { + emsg(_(e_error_while_writing)); + return FAIL; + } + return OK; +} + +/* + * Convert a blob to a readable form: "0z00112233.44556677.8899" + */ + char_u * +blob2string(blob_T *blob, char_u **tofree, char_u *numbuf) +{ + int i; + garray_T ga; + + if (blob == NULL) + { + *tofree = NULL; + return (char_u *)"0z"; + } + + // Store bytes in the growarray. + ga_init2(&ga, 1, 4000); + ga_concat(&ga, (char_u *)"0z"); + for (i = 0; i < blob_len(blob); i++) + { + if (i > 0 && (i & 3) == 0) + ga_concat(&ga, (char_u *)"."); + vim_snprintf((char *)numbuf, NUMBUFLEN, "%02X", blob_get(blob, i)); + ga_concat(&ga, numbuf); + } + ga_append(&ga, NUL); // append a NUL at the end + *tofree = ga.ga_data; + return *tofree; +} + +/* + * Convert a string variable, in the format of blob2string(), to a blob. + * Return NULL when conversion failed. + */ + blob_T * +string2blob(char_u *str) +{ + blob_T *blob = blob_alloc(); + char_u *s = str; + + if (blob == NULL) + return NULL; + if (s[0] != '0' || (s[1] != 'z' && s[1] != 'Z')) + goto failed; + s += 2; + while (vim_isxdigit(*s)) + { + if (!vim_isxdigit(s[1])) + goto failed; + ga_append(&blob->bv_ga, (hex2nr(s[0]) << 4) + hex2nr(s[1])); + s += 2; + if (*s == '.' && vim_isxdigit(s[1])) + ++s; + } + if (*skipwhite(s) != NUL) + goto failed; // text after final digit + + ++blob->bv_refcount; + return blob; + +failed: + blob_free(blob); + return NULL; +} + +/* + * Returns a slice of 'blob' from index 'n1' to 'n2' in 'rettv'. The length of + * the blob is 'len'. Returns an empty blob if the indexes are out of range. + */ + static int +blob_slice( + blob_T *blob, + long len, + varnumber_T n1, + varnumber_T n2, + int exclusive, + typval_T *rettv) +{ + if (n1 < 0) + { + n1 = len + n1; + if (n1 < 0) + n1 = 0; + } + if (n2 < 0) + n2 = len + n2; + else if (n2 >= len) + n2 = len - (exclusive ? 0 : 1); + if (exclusive) + --n2; + if (n1 >= len || n2 < 0 || n1 > n2) + { + clear_tv(rettv); + rettv->v_type = VAR_BLOB; + rettv->vval.v_blob = NULL; + } + else + { + blob_T *new_blob = blob_alloc(); + long i; + + if (new_blob != NULL) + { + if (ga_grow(&new_blob->bv_ga, n2 - n1 + 1) == FAIL) + { + blob_free(new_blob); + return FAIL; + } + new_blob->bv_ga.ga_len = n2 - n1 + 1; + for (i = n1; i <= n2; i++) + blob_set(new_blob, i - n1, blob_get(blob, i)); + + clear_tv(rettv); + rettv_blob_set(rettv, new_blob); + } + } + + return OK; +} + +/* + * Return the byte value in 'blob' at index 'idx' in 'rettv'. If the index is + * too big or negative that is an error. The length of the blob is 'len'. + */ + static int +blob_index( + blob_T *blob, + int len, + varnumber_T idx, + typval_T *rettv) +{ + // The resulting variable is a byte value. + // If the index is too big or negative that is an error. + if (idx < 0) + idx = len + idx; + if (idx < len && idx >= 0) + { + int v = blob_get(blob, idx); + + clear_tv(rettv); + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = v; + } + else + { + semsg(_(e_blob_index_out_of_range_nr), idx); + return FAIL; + } + + return OK; +} + + int +blob_slice_or_index( + blob_T *blob, + int is_range, + varnumber_T n1, + varnumber_T n2, + int exclusive, + typval_T *rettv) +{ + long len = blob_len(blob); + + if (is_range) + return blob_slice(blob, len, n1, n2, exclusive, rettv); + else + return blob_index(blob, len, n1, rettv); + return OK; +} + +/* + * Check if "n1"- is a valid index for a blobl with length "bloblen". + */ + int +check_blob_index(long bloblen, varnumber_T n1, int quiet) +{ + if (n1 < 0 || n1 > bloblen) + { + if (!quiet) + semsg(_(e_blob_index_out_of_range_nr), n1); + return FAIL; + } + return OK; +} + +/* + * Check if "n1"-"n2" is a valid range for a blob with length "bloblen". + */ + int +check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet) +{ + if (n2 < 0 || n2 >= bloblen || n2 < n1) + { + if (!quiet) + semsg(_(e_blob_index_out_of_range_nr), n2); + return FAIL; + } + return OK; +} + +/* + * Set bytes "n1" to "n2" (inclusive) in "dest" to the value of "src". + * Caller must make sure "src" is a blob. + * Returns FAIL if the number of bytes does not match. + */ + int +blob_set_range(blob_T *dest, long n1, long n2, typval_T *src) +{ + int il, ir; + + if (n2 - n1 + 1 != blob_len(src->vval.v_blob)) + { + emsg(_(e_blob_value_does_not_have_right_number_of_bytes)); + return FAIL; + } + + ir = 0; + for (il = n1; il <= n2; il++) + blob_set(dest, il, blob_get(src->vval.v_blob, ir++)); + return OK; +} + +/* + * "add(blob, item)" function + */ + void +blob_add(typval_T *argvars, typval_T *rettv) +{ + blob_T *b = argvars[0].vval.v_blob; + int error = FALSE; + varnumber_T n; + + if (b == NULL) + { + if (in_vim9script()) + emsg(_(e_cannot_add_to_null_blob)); + return; + } + + if (value_check_lock(b->bv_lock, (char_u *)N_("add() argument"), TRUE)) + return; + + n = tv_get_number_chk(&argvars[1], &error); + if (error) + return; + + ga_append(&b->bv_ga, (int)n); + copy_tv(&argvars[0], rettv); +} + +/* + * "remove({blob}, {idx} [, {end}])" function + */ + void +blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg) +{ + blob_T *b = argvars[0].vval.v_blob; + blob_T *newblob; + int error = FALSE; + long idx; + long end; + int len; + char_u *p; + + if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TRUE)) + return; + + idx = (long)tv_get_number_chk(&argvars[1], &error); + if (error) + return; + + len = blob_len(b); + + if (idx < 0) + // count from the end + idx = len + idx; + if (idx < 0 || idx >= len) + { + semsg(_(e_blob_index_out_of_range_nr), idx); + return; + } + if (argvars[2].v_type == VAR_UNKNOWN) + { + // Remove one item, return its value. + p = (char_u *)b->bv_ga.ga_data; + rettv->vval.v_number = (varnumber_T) *(p + idx); + mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1); + --b->bv_ga.ga_len; + return; + } + + // Remove range of items, return blob with values. + end = (long)tv_get_number_chk(&argvars[2], &error); + if (error) + return; + if (end < 0) + // count from the end + end = len + end; + if (end >= len || idx > end) + { + semsg(_(e_blob_index_out_of_range_nr), end); + return; + } + newblob = blob_alloc(); + if (newblob == NULL) + return; + newblob->bv_ga.ga_len = end - idx + 1; + if (ga_grow(&newblob->bv_ga, end - idx + 1) == FAIL) + { + vim_free(newblob); + return; + } + p = (char_u *)b->bv_ga.ga_data; + mch_memmove((char_u *)newblob->bv_ga.ga_data, p + idx, + (size_t)(end - idx + 1)); + ++newblob->bv_refcount; + rettv->v_type = VAR_BLOB; + rettv->vval.v_blob = newblob; + + if (len - end - 1 > 0) + mch_memmove(p + idx, p + end + 1, (size_t)(len - end - 1)); + b->bv_ga.ga_len -= end - idx + 1; +} + +/* + * Implementation of map() and filter() for a Blob. Apply "expr" to every + * number in Blob "blob_arg" and return the result in "rettv". + */ + void +blob_filter_map( + blob_T *blob_arg, + filtermap_T filtermap, + typval_T *expr, + typval_T *rettv) +{ + blob_T *b; + int i; + typval_T tv; + varnumber_T val; + blob_T *b_ret; + int idx = 0; + int rem; + typval_T newtv; + funccall_T *fc; + + if (filtermap == FILTERMAP_MAPNEW) + { + rettv->v_type = VAR_BLOB; + rettv->vval.v_blob = NULL; + } + if ((b = blob_arg) == NULL) + return; + + b_ret = b; + if (filtermap == FILTERMAP_MAPNEW) + { + if (blob_copy(b, rettv) == FAIL) + return; + b_ret = rettv->vval.v_blob; + } + + // set_vim_var_nr() doesn't set the type + set_vim_var_type(VV_KEY, VAR_NUMBER); + + // Create one funccal_T for all eval_expr_typval() calls. + fc = eval_expr_get_funccal(expr, &newtv); + + for (i = 0; i < b->bv_ga.ga_len; i++) + { + tv.v_type = VAR_NUMBER; + val = blob_get(b, i); + tv.vval.v_number = val; + set_vim_var_nr(VV_KEY, idx); + if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL + || did_emsg) + break; + if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL) + { + clear_tv(&newtv); + emsg(_(e_invalid_operation_for_blob)); + break; + } + if (filtermap != FILTERMAP_FILTER) + { + if (newtv.vval.v_number != val) + blob_set(b_ret, i, newtv.vval.v_number); + } + else if (rem) + { + char_u *p = (char_u *)blob_arg->bv_ga.ga_data; + + mch_memmove(p + i, p + i + 1, + (size_t)b->bv_ga.ga_len - i - 1); + --b->bv_ga.ga_len; + --i; + } + ++idx; + } + + if (fc != NULL) + remove_funccal(); +} + +/* + * "insert(blob, {item} [, {idx}])" function + */ + void +blob_insert_func(typval_T *argvars, typval_T *rettv) +{ + blob_T *b = argvars[0].vval.v_blob; + long before = 0; + int error = FALSE; + int val, len; + char_u *p; + + if (b == NULL) + { + if (in_vim9script()) + emsg(_(e_cannot_add_to_null_blob)); + return; + } + + if (value_check_lock(b->bv_lock, (char_u *)N_("insert() argument"), TRUE)) + return; + + len = blob_len(b); + if (argvars[2].v_type != VAR_UNKNOWN) + { + before = (long)tv_get_number_chk(&argvars[2], &error); + if (error) + return; // type error; errmsg already given + if (before < 0 || before > len) + { + semsg(_(e_invalid_argument_str), tv_get_string(&argvars[2])); + return; + } + } + val = tv_get_number_chk(&argvars[1], &error); + if (error) + return; + if (val < 0 || val > 255) + { + semsg(_(e_invalid_argument_str), tv_get_string(&argvars[1])); + return; + } + + if (ga_grow(&b->bv_ga, 1) == FAIL) + return; + p = (char_u *)b->bv_ga.ga_data; + mch_memmove(p + before + 1, p + before, (size_t)len - before); + *(p + before) = val; + ++b->bv_ga.ga_len; + + copy_tv(&argvars[0], rettv); +} + +/* + * Implementation of reduce() for Blob "argvars[0]" using the function "expr" + * starting with the optional initial value "argvars[2]" and return the result + * in "rettv". + */ + void +blob_reduce( + typval_T *argvars, + typval_T *expr, + typval_T *rettv) +{ + blob_T *b = argvars[0].vval.v_blob; + int called_emsg_start = called_emsg; + int r; + typval_T initial; + typval_T argv[3]; + int i; + + if (argvars[2].v_type == VAR_UNKNOWN) + { + if (b == NULL || b->bv_ga.ga_len == 0) + { + semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "Blob"); + return; + } + initial.v_type = VAR_NUMBER; + initial.vval.v_number = blob_get(b, 0); + i = 1; + } + else if (check_for_number_arg(argvars, 2) == FAIL) + return; + else + { + initial = argvars[2]; + i = 0; + } + + copy_tv(&initial, rettv); + if (b == NULL) + return; + + for ( ; i < b->bv_ga.ga_len; i++) + { + argv[0] = *rettv; + argv[1].v_type = VAR_NUMBER; + argv[1].vval.v_number = blob_get(b, i); + + r = eval_expr_typval(expr, argv, 2, NULL, rettv); + + clear_tv(&argv[0]); + if (r == FAIL || called_emsg != called_emsg_start) + return; + } +} + +/* + * "reverse({blob})" function + */ + void +blob_reverse(blob_T *b, typval_T *rettv) +{ + int i, len = blob_len(b); + + for (i = 0; i < len / 2; i++) + { + int tmp = blob_get(b, i); + + blob_set(b, i, blob_get(b, len - i - 1)); + blob_set(b, len - i - 1, tmp); + } + rettv_blob_set(rettv, b); +} + +/* + * blob2list() function + */ + void +f_blob2list(typval_T *argvars, typval_T *rettv) +{ + blob_T *blob; + list_T *l; + int i; + + if (rettv_list_alloc(rettv) == FAIL) + return; + + if (check_for_blob_arg(argvars, 0) == FAIL) + return; + + blob = argvars->vval.v_blob; + l = rettv->vval.v_list; + for (i = 0; i < blob_len(blob); i++) + list_append_number(l, blob_get(blob, i)); +} + +/* + * list2blob() function + */ + void +f_list2blob(typval_T *argvars, typval_T *rettv) +{ + list_T *l; + listitem_T *li; + blob_T *blob; + + if (rettv_blob_alloc(rettv) == FAIL) + return; + blob = rettv->vval.v_blob; + + if (check_for_list_arg(argvars, 0) == FAIL) + return; + + l = argvars->vval.v_list; + if (l == NULL) + return; + + CHECK_LIST_MATERIALIZE(l); + FOR_ALL_LIST_ITEMS(l, li) + { + int error; + varnumber_T n; + + error = FALSE; + n = tv_get_number_chk(&li->li_tv, &error); + if (error == TRUE || n < 0 || n > 255) + { + if (!error) + semsg(_(e_invalid_value_for_blob_nr), n); + ga_clear(&blob->bv_ga); + return; + } + ga_append(&blob->bv_ga, n); + } +} + +#endif // defined(FEAT_EVAL) diff --git a/src/blowfish.c b/src/blowfish.c new file mode 100644 index 0000000..88d4bce --- /dev/null +++ b/src/blowfish.c @@ -0,0 +1,688 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + * + * Blowfish encryption for Vim; in Blowfish cipher feedback mode. + * Contributed by Mohsin Ahmed, http://www.cs.albany.edu/~mosh + * Based on http://www.schneier.com/blowfish.html by Bruce Schneier. + * + * There are two variants: + * - The old one "blowfish" has a flaw which makes it much easier to crack the + * key. To see this, make a text file with one line of 1000 "x" characters + * and write it encrypted. Use "xxd" to inspect the bytes in the file. You + * will see that a block of 8 bytes repeats 8 times. + * - The new one "blowfish2" is better. It uses an 8 byte CFB to avoid the + * repeats. + */ + +#include "vim.h" + +#if defined(FEAT_CRYPT) || defined(PROTO) + +#define BF_BLOCK 8 +#define BF_BLOCK_MASK 7 +#define BF_MAX_CFB_LEN (8 * BF_BLOCK) + +typedef union { + UINT32_T ul[2]; + char_u uc[8]; +} block8; + +#if defined(MSWIN) + // MS-Windows is always little endian +#else +# ifdef HAVE_CONFIG_H + // in configure.ac AC_C_BIGENDIAN() defines WORDS_BIGENDIAN when needed +# else +# error Please change this code to define WORDS_BIGENDIAN for big-endian machines. +# endif +#endif + +// The state of encryption, referenced by cryptstate_T. +typedef struct { + UINT32_T pax[18]; // P-array + UINT32_T sbx[4][256]; // S-boxes + int randbyte_offset; + int update_offset; + char_u cfb_buffer[BF_MAX_CFB_LEN]; // up to 64 bytes used + int cfb_len; // size of cfb_buffer actually used +} bf_state_T; + + +// Blowfish code +static UINT32_T pax_init[18] = { + 0x243f6a88u, 0x85a308d3u, 0x13198a2eu, + 0x03707344u, 0xa4093822u, 0x299f31d0u, + 0x082efa98u, 0xec4e6c89u, 0x452821e6u, + 0x38d01377u, 0xbe5466cfu, 0x34e90c6cu, + 0xc0ac29b7u, 0xc97c50ddu, 0x3f84d5b5u, + 0xb5470917u, 0x9216d5d9u, 0x8979fb1bu +}; + +static UINT32_T sbx_init[4][256] = { + {0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u, + 0xb8e1afedu, 0x6a267e96u, 0xba7c9045u, 0xf12c7f99u, + 0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u, + 0x636920d8u, 0x71574e69u, 0xa458fea3u, 0xf4933d7eu, + 0x0d95748fu, 0x728eb658u, 0x718bcd58u, 0x82154aeeu, + 0x7b54a41du, 0xc25a59b5u, 0x9c30d539u, 0x2af26013u, + 0xc5d1b023u, 0x286085f0u, 0xca417918u, 0xb8db38efu, + 0x8e79dcb0u, 0x603a180eu, 0x6c9e0e8bu, 0xb01e8a3eu, + 0xd71577c1u, 0xbd314b27u, 0x78af2fdau, 0x55605c60u, + 0xe65525f3u, 0xaa55ab94u, 0x57489862u, 0x63e81440u, + 0x55ca396au, 0x2aab10b6u, 0xb4cc5c34u, 0x1141e8ceu, + 0xa15486afu, 0x7c72e993u, 0xb3ee1411u, 0x636fbc2au, + 0x2ba9c55du, 0x741831f6u, 0xce5c3e16u, 0x9b87931eu, + 0xafd6ba33u, 0x6c24cf5cu, 0x7a325381u, 0x28958677u, + 0x3b8f4898u, 0x6b4bb9afu, 0xc4bfe81bu, 0x66282193u, + 0x61d809ccu, 0xfb21a991u, 0x487cac60u, 0x5dec8032u, + 0xef845d5du, 0xe98575b1u, 0xdc262302u, 0xeb651b88u, + 0x23893e81u, 0xd396acc5u, 0x0f6d6ff3u, 0x83f44239u, + 0x2e0b4482u, 0xa4842004u, 0x69c8f04au, 0x9e1f9b5eu, + 0x21c66842u, 0xf6e96c9au, 0x670c9c61u, 0xabd388f0u, + 0x6a51a0d2u, 0xd8542f68u, 0x960fa728u, 0xab5133a3u, + 0x6eef0b6cu, 0x137a3be4u, 0xba3bf050u, 0x7efb2a98u, + 0xa1f1651du, 0x39af0176u, 0x66ca593eu, 0x82430e88u, + 0x8cee8619u, 0x456f9fb4u, 0x7d84a5c3u, 0x3b8b5ebeu, + 0xe06f75d8u, 0x85c12073u, 0x401a449fu, 0x56c16aa6u, + 0x4ed3aa62u, 0x363f7706u, 0x1bfedf72u, 0x429b023du, + 0x37d0d724u, 0xd00a1248u, 0xdb0fead3u, 0x49f1c09bu, + 0x075372c9u, 0x80991b7bu, 0x25d479d8u, 0xf6e8def7u, + 0xe3fe501au, 0xb6794c3bu, 0x976ce0bdu, 0x04c006bau, + 0xc1a94fb6u, 0x409f60c4u, 0x5e5c9ec2u, 0x196a2463u, + 0x68fb6fafu, 0x3e6c53b5u, 0x1339b2ebu, 0x3b52ec6fu, + 0x6dfc511fu, 0x9b30952cu, 0xcc814544u, 0xaf5ebd09u, + 0xbee3d004u, 0xde334afdu, 0x660f2807u, 0x192e4bb3u, + 0xc0cba857u, 0x45c8740fu, 0xd20b5f39u, 0xb9d3fbdbu, + 0x5579c0bdu, 0x1a60320au, 0xd6a100c6u, 0x402c7279u, + 0x679f25feu, 0xfb1fa3ccu, 0x8ea5e9f8u, 0xdb3222f8u, + 0x3c7516dfu, 0xfd616b15u, 0x2f501ec8u, 0xad0552abu, + 0x323db5fau, 0xfd238760u, 0x53317b48u, 0x3e00df82u, + 0x9e5c57bbu, 0xca6f8ca0u, 0x1a87562eu, 0xdf1769dbu, + 0xd542a8f6u, 0x287effc3u, 0xac6732c6u, 0x8c4f5573u, + 0x695b27b0u, 0xbbca58c8u, 0xe1ffa35du, 0xb8f011a0u, + 0x10fa3d98u, 0xfd2183b8u, 0x4afcb56cu, 0x2dd1d35bu, + 0x9a53e479u, 0xb6f84565u, 0xd28e49bcu, 0x4bfb9790u, + 0xe1ddf2dau, 0xa4cb7e33u, 0x62fb1341u, 0xcee4c6e8u, + 0xef20cadau, 0x36774c01u, 0xd07e9efeu, 0x2bf11fb4u, + 0x95dbda4du, 0xae909198u, 0xeaad8e71u, 0x6b93d5a0u, + 0xd08ed1d0u, 0xafc725e0u, 0x8e3c5b2fu, 0x8e7594b7u, + 0x8ff6e2fbu, 0xf2122b64u, 0x8888b812u, 0x900df01cu, + 0x4fad5ea0u, 0x688fc31cu, 0xd1cff191u, 0xb3a8c1adu, + 0x2f2f2218u, 0xbe0e1777u, 0xea752dfeu, 0x8b021fa1u, + 0xe5a0cc0fu, 0xb56f74e8u, 0x18acf3d6u, 0xce89e299u, + 0xb4a84fe0u, 0xfd13e0b7u, 0x7cc43b81u, 0xd2ada8d9u, + 0x165fa266u, 0x80957705u, 0x93cc7314u, 0x211a1477u, + 0xe6ad2065u, 0x77b5fa86u, 0xc75442f5u, 0xfb9d35cfu, + 0xebcdaf0cu, 0x7b3e89a0u, 0xd6411bd3u, 0xae1e7e49u, + 0x00250e2du, 0x2071b35eu, 0x226800bbu, 0x57b8e0afu, + 0x2464369bu, 0xf009b91eu, 0x5563911du, 0x59dfa6aau, + 0x78c14389u, 0xd95a537fu, 0x207d5ba2u, 0x02e5b9c5u, + 0x83260376u, 0x6295cfa9u, 0x11c81968u, 0x4e734a41u, + 0xb3472dcau, 0x7b14a94au, 0x1b510052u, 0x9a532915u, + 0xd60f573fu, 0xbc9bc6e4u, 0x2b60a476u, 0x81e67400u, + 0x08ba6fb5u, 0x571be91fu, 0xf296ec6bu, 0x2a0dd915u, + 0xb6636521u, 0xe7b9f9b6u, 0xff34052eu, 0xc5855664u, + 0x53b02d5du, 0xa99f8fa1u, 0x08ba4799u, 0x6e85076au}, + {0x4b7a70e9u, 0xb5b32944u, 0xdb75092eu, 0xc4192623u, + 0xad6ea6b0u, 0x49a7df7du, 0x9cee60b8u, 0x8fedb266u, + 0xecaa8c71u, 0x699a17ffu, 0x5664526cu, 0xc2b19ee1u, + 0x193602a5u, 0x75094c29u, 0xa0591340u, 0xe4183a3eu, + 0x3f54989au, 0x5b429d65u, 0x6b8fe4d6u, 0x99f73fd6u, + 0xa1d29c07u, 0xefe830f5u, 0x4d2d38e6u, 0xf0255dc1u, + 0x4cdd2086u, 0x8470eb26u, 0x6382e9c6u, 0x021ecc5eu, + 0x09686b3fu, 0x3ebaefc9u, 0x3c971814u, 0x6b6a70a1u, + 0x687f3584u, 0x52a0e286u, 0xb79c5305u, 0xaa500737u, + 0x3e07841cu, 0x7fdeae5cu, 0x8e7d44ecu, 0x5716f2b8u, + 0xb03ada37u, 0xf0500c0du, 0xf01c1f04u, 0x0200b3ffu, + 0xae0cf51au, 0x3cb574b2u, 0x25837a58u, 0xdc0921bdu, + 0xd19113f9u, 0x7ca92ff6u, 0x94324773u, 0x22f54701u, + 0x3ae5e581u, 0x37c2dadcu, 0xc8b57634u, 0x9af3dda7u, + 0xa9446146u, 0x0fd0030eu, 0xecc8c73eu, 0xa4751e41u, + 0xe238cd99u, 0x3bea0e2fu, 0x3280bba1u, 0x183eb331u, + 0x4e548b38u, 0x4f6db908u, 0x6f420d03u, 0xf60a04bfu, + 0x2cb81290u, 0x24977c79u, 0x5679b072u, 0xbcaf89afu, + 0xde9a771fu, 0xd9930810u, 0xb38bae12u, 0xdccf3f2eu, + 0x5512721fu, 0x2e6b7124u, 0x501adde6u, 0x9f84cd87u, + 0x7a584718u, 0x7408da17u, 0xbc9f9abcu, 0xe94b7d8cu, + 0xec7aec3au, 0xdb851dfau, 0x63094366u, 0xc464c3d2u, + 0xef1c1847u, 0x3215d908u, 0xdd433b37u, 0x24c2ba16u, + 0x12a14d43u, 0x2a65c451u, 0x50940002u, 0x133ae4ddu, + 0x71dff89eu, 0x10314e55u, 0x81ac77d6u, 0x5f11199bu, + 0x043556f1u, 0xd7a3c76bu, 0x3c11183bu, 0x5924a509u, + 0xf28fe6edu, 0x97f1fbfau, 0x9ebabf2cu, 0x1e153c6eu, + 0x86e34570u, 0xeae96fb1u, 0x860e5e0au, 0x5a3e2ab3u, + 0x771fe71cu, 0x4e3d06fau, 0x2965dcb9u, 0x99e71d0fu, + 0x803e89d6u, 0x5266c825u, 0x2e4cc978u, 0x9c10b36au, + 0xc6150ebau, 0x94e2ea78u, 0xa5fc3c53u, 0x1e0a2df4u, + 0xf2f74ea7u, 0x361d2b3du, 0x1939260fu, 0x19c27960u, + 0x5223a708u, 0xf71312b6u, 0xebadfe6eu, 0xeac31f66u, + 0xe3bc4595u, 0xa67bc883u, 0xb17f37d1u, 0x018cff28u, + 0xc332ddefu, 0xbe6c5aa5u, 0x65582185u, 0x68ab9802u, + 0xeecea50fu, 0xdb2f953bu, 0x2aef7dadu, 0x5b6e2f84u, + 0x1521b628u, 0x29076170u, 0xecdd4775u, 0x619f1510u, + 0x13cca830u, 0xeb61bd96u, 0x0334fe1eu, 0xaa0363cfu, + 0xb5735c90u, 0x4c70a239u, 0xd59e9e0bu, 0xcbaade14u, + 0xeecc86bcu, 0x60622ca7u, 0x9cab5cabu, 0xb2f3846eu, + 0x648b1eafu, 0x19bdf0cau, 0xa02369b9u, 0x655abb50u, + 0x40685a32u, 0x3c2ab4b3u, 0x319ee9d5u, 0xc021b8f7u, + 0x9b540b19u, 0x875fa099u, 0x95f7997eu, 0x623d7da8u, + 0xf837889au, 0x97e32d77u, 0x11ed935fu, 0x16681281u, + 0x0e358829u, 0xc7e61fd6u, 0x96dedfa1u, 0x7858ba99u, + 0x57f584a5u, 0x1b227263u, 0x9b83c3ffu, 0x1ac24696u, + 0xcdb30aebu, 0x532e3054u, 0x8fd948e4u, 0x6dbc3128u, + 0x58ebf2efu, 0x34c6ffeau, 0xfe28ed61u, 0xee7c3c73u, + 0x5d4a14d9u, 0xe864b7e3u, 0x42105d14u, 0x203e13e0u, + 0x45eee2b6u, 0xa3aaabeau, 0xdb6c4f15u, 0xfacb4fd0u, + 0xc742f442u, 0xef6abbb5u, 0x654f3b1du, 0x41cd2105u, + 0xd81e799eu, 0x86854dc7u, 0xe44b476au, 0x3d816250u, + 0xcf62a1f2u, 0x5b8d2646u, 0xfc8883a0u, 0xc1c7b6a3u, + 0x7f1524c3u, 0x69cb7492u, 0x47848a0bu, 0x5692b285u, + 0x095bbf00u, 0xad19489du, 0x1462b174u, 0x23820e00u, + 0x58428d2au, 0x0c55f5eau, 0x1dadf43eu, 0x233f7061u, + 0x3372f092u, 0x8d937e41u, 0xd65fecf1u, 0x6c223bdbu, + 0x7cde3759u, 0xcbee7460u, 0x4085f2a7u, 0xce77326eu, + 0xa6078084u, 0x19f8509eu, 0xe8efd855u, 0x61d99735u, + 0xa969a7aau, 0xc50c06c2u, 0x5a04abfcu, 0x800bcadcu, + 0x9e447a2eu, 0xc3453484u, 0xfdd56705u, 0x0e1e9ec9u, + 0xdb73dbd3u, 0x105588cdu, 0x675fda79u, 0xe3674340u, + 0xc5c43465u, 0x713e38d8u, 0x3d28f89eu, 0xf16dff20u, + 0x153e21e7u, 0x8fb03d4au, 0xe6e39f2bu, 0xdb83adf7u}, + {0xe93d5a68u, 0x948140f7u, 0xf64c261cu, 0x94692934u, + 0x411520f7u, 0x7602d4f7u, 0xbcf46b2eu, 0xd4a20068u, + 0xd4082471u, 0x3320f46au, 0x43b7d4b7u, 0x500061afu, + 0x1e39f62eu, 0x97244546u, 0x14214f74u, 0xbf8b8840u, + 0x4d95fc1du, 0x96b591afu, 0x70f4ddd3u, 0x66a02f45u, + 0xbfbc09ecu, 0x03bd9785u, 0x7fac6dd0u, 0x31cb8504u, + 0x96eb27b3u, 0x55fd3941u, 0xda2547e6u, 0xabca0a9au, + 0x28507825u, 0x530429f4u, 0x0a2c86dau, 0xe9b66dfbu, + 0x68dc1462u, 0xd7486900u, 0x680ec0a4u, 0x27a18deeu, + 0x4f3ffea2u, 0xe887ad8cu, 0xb58ce006u, 0x7af4d6b6u, + 0xaace1e7cu, 0xd3375fecu, 0xce78a399u, 0x406b2a42u, + 0x20fe9e35u, 0xd9f385b9u, 0xee39d7abu, 0x3b124e8bu, + 0x1dc9faf7u, 0x4b6d1856u, 0x26a36631u, 0xeae397b2u, + 0x3a6efa74u, 0xdd5b4332u, 0x6841e7f7u, 0xca7820fbu, + 0xfb0af54eu, 0xd8feb397u, 0x454056acu, 0xba489527u, + 0x55533a3au, 0x20838d87u, 0xfe6ba9b7u, 0xd096954bu, + 0x55a867bcu, 0xa1159a58u, 0xcca92963u, 0x99e1db33u, + 0xa62a4a56u, 0x3f3125f9u, 0x5ef47e1cu, 0x9029317cu, + 0xfdf8e802u, 0x04272f70u, 0x80bb155cu, 0x05282ce3u, + 0x95c11548u, 0xe4c66d22u, 0x48c1133fu, 0xc70f86dcu, + 0x07f9c9eeu, 0x41041f0fu, 0x404779a4u, 0x5d886e17u, + 0x325f51ebu, 0xd59bc0d1u, 0xf2bcc18fu, 0x41113564u, + 0x257b7834u, 0x602a9c60u, 0xdff8e8a3u, 0x1f636c1bu, + 0x0e12b4c2u, 0x02e1329eu, 0xaf664fd1u, 0xcad18115u, + 0x6b2395e0u, 0x333e92e1u, 0x3b240b62u, 0xeebeb922u, + 0x85b2a20eu, 0xe6ba0d99u, 0xde720c8cu, 0x2da2f728u, + 0xd0127845u, 0x95b794fdu, 0x647d0862u, 0xe7ccf5f0u, + 0x5449a36fu, 0x877d48fau, 0xc39dfd27u, 0xf33e8d1eu, + 0x0a476341u, 0x992eff74u, 0x3a6f6eabu, 0xf4f8fd37u, + 0xa812dc60u, 0xa1ebddf8u, 0x991be14cu, 0xdb6e6b0du, + 0xc67b5510u, 0x6d672c37u, 0x2765d43bu, 0xdcd0e804u, + 0xf1290dc7u, 0xcc00ffa3u, 0xb5390f92u, 0x690fed0bu, + 0x667b9ffbu, 0xcedb7d9cu, 0xa091cf0bu, 0xd9155ea3u, + 0xbb132f88u, 0x515bad24u, 0x7b9479bfu, 0x763bd6ebu, + 0x37392eb3u, 0xcc115979u, 0x8026e297u, 0xf42e312du, + 0x6842ada7u, 0xc66a2b3bu, 0x12754cccu, 0x782ef11cu, + 0x6a124237u, 0xb79251e7u, 0x06a1bbe6u, 0x4bfb6350u, + 0x1a6b1018u, 0x11caedfau, 0x3d25bdd8u, 0xe2e1c3c9u, + 0x44421659u, 0x0a121386u, 0xd90cec6eu, 0xd5abea2au, + 0x64af674eu, 0xda86a85fu, 0xbebfe988u, 0x64e4c3feu, + 0x9dbc8057u, 0xf0f7c086u, 0x60787bf8u, 0x6003604du, + 0xd1fd8346u, 0xf6381fb0u, 0x7745ae04u, 0xd736fcccu, + 0x83426b33u, 0xf01eab71u, 0xb0804187u, 0x3c005e5fu, + 0x77a057beu, 0xbde8ae24u, 0x55464299u, 0xbf582e61u, + 0x4e58f48fu, 0xf2ddfda2u, 0xf474ef38u, 0x8789bdc2u, + 0x5366f9c3u, 0xc8b38e74u, 0xb475f255u, 0x46fcd9b9u, + 0x7aeb2661u, 0x8b1ddf84u, 0x846a0e79u, 0x915f95e2u, + 0x466e598eu, 0x20b45770u, 0x8cd55591u, 0xc902de4cu, + 0xb90bace1u, 0xbb8205d0u, 0x11a86248u, 0x7574a99eu, + 0xb77f19b6u, 0xe0a9dc09u, 0x662d09a1u, 0xc4324633u, + 0xe85a1f02u, 0x09f0be8cu, 0x4a99a025u, 0x1d6efe10u, + 0x1ab93d1du, 0x0ba5a4dfu, 0xa186f20fu, 0x2868f169u, + 0xdcb7da83u, 0x573906feu, 0xa1e2ce9bu, 0x4fcd7f52u, + 0x50115e01u, 0xa70683fau, 0xa002b5c4u, 0x0de6d027u, + 0x9af88c27u, 0x773f8641u, 0xc3604c06u, 0x61a806b5u, + 0xf0177a28u, 0xc0f586e0u, 0x006058aau, 0x30dc7d62u, + 0x11e69ed7u, 0x2338ea63u, 0x53c2dd94u, 0xc2c21634u, + 0xbbcbee56u, 0x90bcb6deu, 0xebfc7da1u, 0xce591d76u, + 0x6f05e409u, 0x4b7c0188u, 0x39720a3du, 0x7c927c24u, + 0x86e3725fu, 0x724d9db9u, 0x1ac15bb4u, 0xd39eb8fcu, + 0xed545578u, 0x08fca5b5u, 0xd83d7cd3u, 0x4dad0fc4u, + 0x1e50ef5eu, 0xb161e6f8u, 0xa28514d9u, 0x6c51133cu, + 0x6fd5c7e7u, 0x56e14ec4u, 0x362abfceu, 0xddc6c837u, + 0xd79a3234u, 0x92638212u, 0x670efa8eu, 0x406000e0u}, + {0x3a39ce37u, 0xd3faf5cfu, 0xabc27737u, 0x5ac52d1bu, + 0x5cb0679eu, 0x4fa33742u, 0xd3822740u, 0x99bc9bbeu, + 0xd5118e9du, 0xbf0f7315u, 0xd62d1c7eu, 0xc700c47bu, + 0xb78c1b6bu, 0x21a19045u, 0xb26eb1beu, 0x6a366eb4u, + 0x5748ab2fu, 0xbc946e79u, 0xc6a376d2u, 0x6549c2c8u, + 0x530ff8eeu, 0x468dde7du, 0xd5730a1du, 0x4cd04dc6u, + 0x2939bbdbu, 0xa9ba4650u, 0xac9526e8u, 0xbe5ee304u, + 0xa1fad5f0u, 0x6a2d519au, 0x63ef8ce2u, 0x9a86ee22u, + 0xc089c2b8u, 0x43242ef6u, 0xa51e03aau, 0x9cf2d0a4u, + 0x83c061bau, 0x9be96a4du, 0x8fe51550u, 0xba645bd6u, + 0x2826a2f9u, 0xa73a3ae1u, 0x4ba99586u, 0xef5562e9u, + 0xc72fefd3u, 0xf752f7dau, 0x3f046f69u, 0x77fa0a59u, + 0x80e4a915u, 0x87b08601u, 0x9b09e6adu, 0x3b3ee593u, + 0xe990fd5au, 0x9e34d797u, 0x2cf0b7d9u, 0x022b8b51u, + 0x96d5ac3au, 0x017da67du, 0xd1cf3ed6u, 0x7c7d2d28u, + 0x1f9f25cfu, 0xadf2b89bu, 0x5ad6b472u, 0x5a88f54cu, + 0xe029ac71u, 0xe019a5e6u, 0x47b0acfdu, 0xed93fa9bu, + 0xe8d3c48du, 0x283b57ccu, 0xf8d56629u, 0x79132e28u, + 0x785f0191u, 0xed756055u, 0xf7960e44u, 0xe3d35e8cu, + 0x15056dd4u, 0x88f46dbau, 0x03a16125u, 0x0564f0bdu, + 0xc3eb9e15u, 0x3c9057a2u, 0x97271aecu, 0xa93a072au, + 0x1b3f6d9bu, 0x1e6321f5u, 0xf59c66fbu, 0x26dcf319u, + 0x7533d928u, 0xb155fdf5u, 0x03563482u, 0x8aba3cbbu, + 0x28517711u, 0xc20ad9f8u, 0xabcc5167u, 0xccad925fu, + 0x4de81751u, 0x3830dc8eu, 0x379d5862u, 0x9320f991u, + 0xea7a90c2u, 0xfb3e7bceu, 0x5121ce64u, 0x774fbe32u, + 0xa8b6e37eu, 0xc3293d46u, 0x48de5369u, 0x6413e680u, + 0xa2ae0810u, 0xdd6db224u, 0x69852dfdu, 0x09072166u, + 0xb39a460au, 0x6445c0ddu, 0x586cdecfu, 0x1c20c8aeu, + 0x5bbef7ddu, 0x1b588d40u, 0xccd2017fu, 0x6bb4e3bbu, + 0xdda26a7eu, 0x3a59ff45u, 0x3e350a44u, 0xbcb4cdd5u, + 0x72eacea8u, 0xfa6484bbu, 0x8d6612aeu, 0xbf3c6f47u, + 0xd29be463u, 0x542f5d9eu, 0xaec2771bu, 0xf64e6370u, + 0x740e0d8du, 0xe75b1357u, 0xf8721671u, 0xaf537d5du, + 0x4040cb08u, 0x4eb4e2ccu, 0x34d2466au, 0x0115af84u, + 0xe1b00428u, 0x95983a1du, 0x06b89fb4u, 0xce6ea048u, + 0x6f3f3b82u, 0x3520ab82u, 0x011a1d4bu, 0x277227f8u, + 0x611560b1u, 0xe7933fdcu, 0xbb3a792bu, 0x344525bdu, + 0xa08839e1u, 0x51ce794bu, 0x2f32c9b7u, 0xa01fbac9u, + 0xe01cc87eu, 0xbcc7d1f6u, 0xcf0111c3u, 0xa1e8aac7u, + 0x1a908749u, 0xd44fbd9au, 0xd0dadecbu, 0xd50ada38u, + 0x0339c32au, 0xc6913667u, 0x8df9317cu, 0xe0b12b4fu, + 0xf79e59b7u, 0x43f5bb3au, 0xf2d519ffu, 0x27d9459cu, + 0xbf97222cu, 0x15e6fc2au, 0x0f91fc71u, 0x9b941525u, + 0xfae59361u, 0xceb69cebu, 0xc2a86459u, 0x12baa8d1u, + 0xb6c1075eu, 0xe3056a0cu, 0x10d25065u, 0xcb03a442u, + 0xe0ec6e0eu, 0x1698db3bu, 0x4c98a0beu, 0x3278e964u, + 0x9f1f9532u, 0xe0d392dfu, 0xd3a0342bu, 0x8971f21eu, + 0x1b0a7441u, 0x4ba3348cu, 0xc5be7120u, 0xc37632d8u, + 0xdf359f8du, 0x9b992f2eu, 0xe60b6f47u, 0x0fe3f11du, + 0xe54cda54u, 0x1edad891u, 0xce6279cfu, 0xcd3e7e6fu, + 0x1618b166u, 0xfd2c1d05u, 0x848fd2c5u, 0xf6fb2299u, + 0xf523f357u, 0xa6327623u, 0x93a83531u, 0x56cccd02u, + 0xacf08162u, 0x5a75ebb5u, 0x6e163697u, 0x88d273ccu, + 0xde966292u, 0x81b949d0u, 0x4c50901bu, 0x71c65614u, + 0xe6c6c7bdu, 0x327a140au, 0x45e1d006u, 0xc3f27b9au, + 0xc9aa53fdu, 0x62a80f00u, 0xbb25bfe2u, 0x35bdd2f6u, + 0x71126905u, 0xb2040222u, 0xb6cbcf7cu, 0xcd769c2bu, + 0x53113ec0u, 0x1640e3d3u, 0x38abbd60u, 0x2547adf0u, + 0xba38209cu, 0xf746ce76u, 0x77afa1c5u, 0x20756060u, + 0x85cbfe4eu, 0x8ae88dd8u, 0x7aaaf9b0u, 0x4cf9aa7eu, + 0x1948c25cu, 0x02fb8a8cu, 0x01c36ae4u, 0xd6ebe1f9u, + 0x90d4f869u, 0xa65cdea0u, 0x3f09252du, 0xc208e69fu, + 0xb74e6132u, 0xce77e25bu, 0x578fdfe3u, 0x3ac372e6u + } +}; + +#define F1(i) \ + xl ^= bfs->pax[i]; \ + xr ^= ((bfs->sbx[0][xl >> 24] + \ + bfs->sbx[1][(xl & 0xFF0000) >> 16]) ^ \ + bfs->sbx[2][(xl & 0xFF00) >> 8]) + \ + bfs->sbx[3][xl & 0xFF]; + +#define F2(i) \ + xr ^= bfs->pax[i]; \ + xl ^= ((bfs->sbx[0][xr >> 24] + \ + bfs->sbx[1][(xr & 0xFF0000) >> 16]) ^ \ + bfs->sbx[2][(xr & 0xFF00) >> 8]) + \ + bfs->sbx[3][xr & 0xFF]; + + static void +bf_e_block( + bf_state_T *bfs, + UINT32_T *p_xl, + UINT32_T *p_xr) +{ + UINT32_T temp; + UINT32_T xl = *p_xl; + UINT32_T xr = *p_xr; + + F1(0) F2(1) + F1(2) F2(3) + F1(4) F2(5) + F1(6) F2(7) + F1(8) F2(9) + F1(10) F2(11) + F1(12) F2(13) + F1(14) F2(15) + xl ^= bfs->pax[16]; + xr ^= bfs->pax[17]; + temp = xl; + xl = xr; + xr = temp; + *p_xl = xl; + *p_xr = xr; +} + + +#ifdef WORDS_BIGENDIAN +# define htonl2(x) \ + x = ((((x) & 0xffL) << 24) | (((x) & 0xff00L) << 8) | \ + (((x) & 0xff0000L) >> 8) | (((x) & 0xff000000L) >> 24)) +#else +# define htonl2(x) +#endif + + static void +bf_e_cblock( + bf_state_T *bfs, + char_u *block) +{ + block8 bk; + + memcpy(bk.uc, block, 8); + htonl2(bk.ul[0]); + htonl2(bk.ul[1]); + bf_e_block(bfs, &bk.ul[0], &bk.ul[1]); + htonl2(bk.ul[0]); + htonl2(bk.ul[1]); + memcpy(block, bk.uc, 8); +} + +/* + * Initialize the crypt method using "password" as the encryption key and + * "salt[salt_len]" as the salt. + */ + static void +bf_key_init( + bf_state_T *bfs, + char_u *password, + char_u *salt, + int salt_len) +{ + int i, j, keypos = 0; + unsigned u; + UINT32_T val, data_l, data_r; + char_u *key; + int keylen; + + // Process the key 1001 times. + // See http://en.wikipedia.org/wiki/Key_strengthening. + key = sha256_key(password, salt, salt_len); + for (i = 0; i < 1000; i++) + key = sha256_key(key, salt, salt_len); + + // Convert the key from 64 hex chars to 32 binary chars. + keylen = (int)STRLEN(key) / 2; + if (keylen == 0) + { + iemsg(_(e_bf_key_init_called_with_empty_password)); + return; + } + for (i = 0; i < keylen; i++) + { + sscanf((char *)&key[i * 2], "%2x", &u); + key[i] = u; + } + + // Use "key" to initialize the P-array ("pax") and S-boxes ("sbx") of + // Blowfish. + mch_memmove(bfs->sbx, sbx_init, 4 * 4 * 256); + + for (i = 0; i < 18; ++i) + { + val = 0; + for (j = 0; j < 4; ++j) + val = (val << 8) | key[keypos++ % keylen]; + bfs->pax[i] = pax_init[i] ^ val; + } + + data_l = data_r = 0; + for (i = 0; i < 18; i += 2) + { + bf_e_block(bfs, &data_l, &data_r); + bfs->pax[i + 0] = data_l; + bfs->pax[i + 1] = data_r; + } + + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 256; j += 2) + { + bf_e_block(bfs, &data_l, &data_r); + bfs->sbx[i][j + 0] = data_l; + bfs->sbx[i][j + 1] = data_r; + } + } +} + +/* + * Blowfish self-test for corrupted tables or instructions. + */ + static int +bf_check_tables( + UINT32_T pax[18], + UINT32_T sbx[4][256], + UINT32_T val) +{ + int i, j; + UINT32_T c = 0; + + for (i = 0; i < 18; i++) + c ^= pax[i]; + for (i = 0; i < 4; i++) + for (j = 0; j < 256; j++) + c ^= sbx[i][j]; + return c == val; +} + +typedef struct { + char_u password[64]; + char_u salt[9]; + char_u plaintxt[9]; + char_u cryptxt[9]; + char_u badcryptxt[9]; // cryptxt when big/little endian is wrong + UINT32_T keysum; +} struct_bf_test_data; + +/* + * Assert bf(password, plaintxt) is cryptxt. + * Assert csum(pax sbx(password)) is keysum. + */ +static struct_bf_test_data bf_test_data[] = { + { + "password", + "salt", + "plaintxt", + "\xad\x3d\xfa\x7f\xe8\xea\x40\xf6", // cryptxt + "\x72\x50\x3b\x38\x10\x60\x22\xa7", // badcryptxt + 0x56701b5du // keysum + }, +}; + +/* + * Return FAIL when there is something wrong with blowfish encryption. + */ + static int +bf_self_test(void) +{ + int i, bn; + int err = 0; + block8 bk; + UINT32_T ui = 0xffffffffUL; + bf_state_T state; + + CLEAR_FIELD(state); + state.cfb_len = BF_MAX_CFB_LEN; + + // We can't simply use sizeof(UINT32_T), it would generate a compiler + // warning. + if (ui != 0xffffffffUL || ui + 1 != 0) + { + err++; + emsg(_(e_sizeof_uint32_isnot_four)); + } + + if (!bf_check_tables(pax_init, sbx_init, 0x6ffa520a)) + err++; + + bn = ARRAY_LENGTH(bf_test_data); + for (i = 0; i < bn; i++) + { + bf_key_init(&state, (char_u *)(bf_test_data[i].password), + bf_test_data[i].salt, + (int)STRLEN(bf_test_data[i].salt)); + if (!bf_check_tables(state.pax, state.sbx, bf_test_data[i].keysum)) + err++; + + // Don't modify bf_test_data[i].plaintxt, self test is idempotent. + memcpy(bk.uc, bf_test_data[i].plaintxt, 8); + bf_e_cblock(&state, bk.uc); + if (memcmp(bk.uc, bf_test_data[i].cryptxt, 8) != 0) + { + if (err == 0 && memcmp(bk.uc, bf_test_data[i].badcryptxt, 8) == 0) + emsg(_(e_blowfish_big_little_endian_use_wrong)); + err++; + } + } + + return err > 0 ? FAIL : OK; +} + +/* + * CFB: Cipher Feedback Mode. + */ + +/* + * Initialize with seed "seed[seed_len]". + */ + static void +bf_cfb_init( + bf_state_T *bfs, + char_u *seed, + int seed_len) +{ + int i, mi; + + bfs->randbyte_offset = bfs->update_offset = 0; + vim_memset(bfs->cfb_buffer, 0, bfs->cfb_len); + if (seed_len > 0) + { + mi = seed_len > bfs->cfb_len ? seed_len : bfs->cfb_len; + for (i = 0; i < mi; i++) + bfs->cfb_buffer[i % bfs->cfb_len] ^= seed[i % seed_len]; + } +} + +#define BF_CFB_UPDATE(bfs, c) \ +{ \ + bfs->cfb_buffer[bfs->update_offset] ^= (char_u)c; \ + if (++bfs->update_offset == bfs->cfb_len) \ + bfs->update_offset = 0; \ +} + +#define BF_RANBYTE(bfs, t) \ +{ \ + if ((bfs->randbyte_offset & BF_BLOCK_MASK) == 0) \ + bf_e_cblock(bfs, &(bfs->cfb_buffer[bfs->randbyte_offset])); \ + t = bfs->cfb_buffer[bfs->randbyte_offset]; \ + if (++bfs->randbyte_offset == bfs->cfb_len) \ + bfs->randbyte_offset = 0; \ +} + +/* + * Encrypt "from[len]" into "to[len]". + * "from" and "to" can be equal to encrypt in place. + */ + void +crypt_blowfish_encode( + cryptstate_T *state, + char_u *from, + size_t len, + char_u *to, + int last UNUSED) +{ + bf_state_T *bfs = state->method_state; + size_t i; + int ztemp, t; + + for (i = 0; i < len; ++i) + { + ztemp = from[i]; + BF_RANBYTE(bfs, t); + BF_CFB_UPDATE(bfs, ztemp); + to[i] = t ^ ztemp; + } +} + +/* + * Decrypt "from[len]" into "to[len]". + */ + void +crypt_blowfish_decode( + cryptstate_T *state, + char_u *from, + size_t len, + char_u *to, + int last UNUSED) +{ + bf_state_T *bfs = state->method_state; + size_t i; + int t; + + for (i = 0; i < len; ++i) + { + BF_RANBYTE(bfs, t); + to[i] = from[i] ^ t; + BF_CFB_UPDATE(bfs, to[i]); + } +} + + int +crypt_blowfish_init( + cryptstate_T *state, + char_u* key, + char_u* salt, + int salt_len, + char_u* seed, + int seed_len) +{ + bf_state_T *bfs = ALLOC_CLEAR_ONE(bf_state_T); + + if (bfs == NULL) + return FAIL; + state->method_state = bfs; + + // "blowfish" uses a 64 byte buffer, causing it to repeat 8 byte groups 8 + // times. "blowfish2" uses an 8 byte buffer to avoid repeating. + bfs->cfb_len = state->method_nr == CRYPT_M_BF ? BF_MAX_CFB_LEN : BF_BLOCK; + + if (blowfish_self_test() == FAIL) + return FAIL; + + bf_key_init(bfs, key, salt, salt_len); + bf_cfb_init(bfs, seed, seed_len); + + return OK; +} + +/* + * Run a test to check if the encryption works as expected. + * Give an error and return FAIL when not. + */ + int +blowfish_self_test(void) +{ + if (sha256_self_test() == FAIL) + { + emsg(_(e_sha256_test_failed)); + return FAIL; + } + if (bf_self_test() == FAIL) + { + emsg(_(e_blowfish_test_failed)); + return FAIL; + } + return OK; +} +#endif // FEAT_CRYPT diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..ff35729 --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,6058 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * buffer.c: functions for dealing with the buffer structure + */ + +/* + * The buffer list is a double linked list of all buffers. + * Each buffer can be in one of these states: + * never loaded: BF_NEVERLOADED is set, only the file name is valid + * not loaded: b_ml.ml_mfp == NULL, no memfile allocated + * hidden: b_nwindows == 0, loaded but not displayed in a window + * normal: loaded and displayed in a window + * + * Instead of storing file names all over the place, each file name is + * stored in the buffer list. It can be referenced by a number. + * + * The current implementation remembers all file names ever used. + */ + +#include "vim.h" + + +#ifdef FEAT_EVAL +// Determines how deeply nested %{} blocks will be evaluated in statusline. +# define MAX_STL_EVAL_DEPTH 100 +#endif + +static void enter_buffer(buf_T *buf); +static void buflist_getfpos(void); +static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, int ignore_case); +static char_u *fname_match(regmatch_T *rmp, char_u *name, int ignore_case); +#ifdef UNIX +static buf_T *buflist_findname_stat(char_u *ffname, stat_T *st); +static int otherfile_buf(buf_T *buf, char_u *ffname, stat_T *stp); +static int buf_same_ino(buf_T *buf, stat_T *stp); +#else +static int otherfile_buf(buf_T *buf, char_u *ffname); +#endif +static int value_changed(char_u *str, char_u **last); +static int append_arg_number(win_T *wp, char_u *buf, int buflen, int add_file); +static void free_buffer(buf_T *); +static void free_buffer_stuff(buf_T *buf, int free_options); +static int bt_nofileread(buf_T *buf); +static void no_write_message_buf(buf_T *buf); + +#ifdef UNIX +# define dev_T dev_t +#else +# define dev_T unsigned +#endif + +#define FOR_ALL_BUFS_FROM_LAST(buf) \ + for ((buf) = lastbuf; (buf) != NULL; (buf) = (buf)->b_prev) + +#if defined(FEAT_QUICKFIX) +static char *msg_loclist = N_("[Location List]"); +static char *msg_qflist = N_("[Quickfix List]"); +#endif + +// Number of times free_buffer() was called. +static int buf_free_count = 0; + +static int top_file_num = 1; // highest file number +static garray_T buf_reuse = GA_EMPTY; // file numbers to recycle + +/* + * Return the highest possible buffer number. + */ + int +get_highest_fnum(void) +{ + return top_file_num - 1; +} + +/* + * Read data from buffer for retrying. + */ + static int +read_buffer( + int read_stdin, // read file from stdin, otherwise fifo + exarg_T *eap, // for forced 'ff' and 'fenc' or NULL + int flags) // extra flags for readfile() +{ + int retval = OK; + linenr_T line_count; + + // Read from the buffer which the text is already filled in and append at + // the end. This makes it possible to retry when 'fileformat' or + // 'fileencoding' was guessed wrong. + line_count = curbuf->b_ml.ml_line_count; + retval = readfile( + read_stdin ? NULL : curbuf->b_ffname, + read_stdin ? NULL : curbuf->b_fname, + line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap, + flags | READ_BUFFER); + if (retval == OK) + { + // Delete the binary lines. + while (--line_count >= 0) + ml_delete((linenr_T)1); + } + else + { + // Delete the converted lines. + while (curbuf->b_ml.ml_line_count > line_count) + ml_delete(line_count); + } + // Put the cursor on the first line. + curwin->w_cursor.lnum = 1; + curwin->w_cursor.col = 0; + + if (read_stdin) + { + // Set or reset 'modified' before executing autocommands, so that + // it can be changed there. + if (!readonlymode && !BUFEMPTY()) + changed(); + else if (retval == OK) + unchanged(curbuf, FALSE, TRUE); + + if (retval == OK) + { +#ifdef FEAT_EVAL + apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE, + curbuf, &retval); +#else + apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf); +#endif + } + } + return retval; +} + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Ensure buffer "buf" is loaded. Does not trigger the swap-exists action. + */ + void +buffer_ensure_loaded(buf_T *buf) +{ + if (buf->b_ml.ml_mfp != NULL) + return; + + aco_save_T aco; + + // Make sure the buffer is in a window. If not then skip it. + aucmd_prepbuf(&aco, buf); + if (curbuf == buf) + { + if (swap_exists_action != SEA_READONLY) + swap_exists_action = SEA_NONE; + open_buffer(FALSE, NULL, 0); + aucmd_restbuf(&aco); + } +} +#endif + +/* + * Open current buffer, that is: open the memfile and read the file into + * memory. + * Return FAIL for failure, OK otherwise. + */ + int +open_buffer( + int read_stdin, // read file from stdin + exarg_T *eap, // for forced 'ff' and 'fenc' or NULL + int flags_arg) // extra flags for readfile() +{ + int flags = flags_arg; + int retval = OK; + bufref_T old_curbuf; +#ifdef FEAT_SYN_HL + long old_tw = curbuf->b_p_tw; +#endif + int read_fifo = FALSE; + + // The 'readonly' flag is only set when BF_NEVERLOADED is being reset. + // When re-entering the same buffer, it should not change, because the + // user may have reset the flag by hand. + if (readonlymode && curbuf->b_ffname != NULL + && (curbuf->b_flags & BF_NEVERLOADED)) + curbuf->b_p_ro = TRUE; + + if (ml_open(curbuf) == FAIL) + { + // There MUST be a memfile, otherwise we can't do anything + // If we can't create one for the current buffer, take another buffer + close_buffer(NULL, curbuf, 0, FALSE, FALSE); + FOR_ALL_BUFFERS(curbuf) + if (curbuf->b_ml.ml_mfp != NULL) + break; + // If there is no memfile at all, exit. + // This is OK, since there are no changes to lose. + if (curbuf == NULL) + { + emsg(_(e_cannot_allocate_any_buffer_exiting)); + + // Don't try to do any saving, with "curbuf" NULL almost nothing + // will work. + v_dying = 2; + getout(2); + } + + emsg(_(e_cannot_allocate_buffer_using_other_one)); + enter_buffer(curbuf); +#ifdef FEAT_SYN_HL + if (old_tw != curbuf->b_p_tw) + check_colorcolumn(curwin); +#endif + return FAIL; + } + + // The autocommands in readfile() may change the buffer, but only AFTER + // reading the file. + set_bufref(&old_curbuf, curbuf); + modified_was_set = FALSE; + + // mark cursor position as being invalid + curwin->w_valid = 0; + + // A buffer without an actual file should not use the buffer name to read a + // file. + if (bt_nofileread(curbuf)) + flags |= READ_NOFILE; + + // Read the file if there is one. + if (curbuf->b_ffname != NULL +#ifdef FEAT_NETBEANS_INTG + && netbeansReadFile +#endif + ) + { + int old_msg_silent = msg_silent; +#ifdef UNIX + int save_bin = curbuf->b_p_bin; + int perm; +#endif +#ifdef FEAT_NETBEANS_INTG + int oldFire = netbeansFireChanges; + + netbeansFireChanges = 0; +#endif +#ifdef UNIX + perm = mch_getperm(curbuf->b_ffname); + if (perm >= 0 && (S_ISFIFO(perm) + || S_ISSOCK(perm) +# ifdef OPEN_CHR_FILES + || (S_ISCHR(perm) && is_dev_fd_file(curbuf->b_ffname)) +# endif + )) + read_fifo = TRUE; + if (read_fifo) + curbuf->b_p_bin = TRUE; +#endif + if (shortmess(SHM_FILEINFO)) + msg_silent = 1; + retval = readfile(curbuf->b_ffname, curbuf->b_fname, + (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap, + flags | READ_NEW | (read_fifo ? READ_FIFO : 0)); +#ifdef UNIX + if (read_fifo) + { + curbuf->b_p_bin = save_bin; + if (retval == OK) + retval = read_buffer(FALSE, eap, flags); + } +#endif + msg_silent = old_msg_silent; +#ifdef FEAT_NETBEANS_INTG + netbeansFireChanges = oldFire; +#endif + // Help buffer is filtered. + if (bt_help(curbuf)) + fix_help_buffer(); + } + else if (read_stdin) + { + int save_bin = curbuf->b_p_bin; + + // First read the text in binary mode into the buffer. + // Then read from that same buffer and append at the end. This makes + // it possible to retry when 'fileformat' or 'fileencoding' was + // guessed wrong. + curbuf->b_p_bin = TRUE; + retval = readfile(NULL, NULL, (linenr_T)0, + (linenr_T)0, (linenr_T)MAXLNUM, NULL, + flags | (READ_NEW + READ_STDIN)); + curbuf->b_p_bin = save_bin; + if (retval == OK) + retval = read_buffer(TRUE, eap, flags); + } + + // if first time loading this buffer, init b_chartab[] + if (curbuf->b_flags & BF_NEVERLOADED) + { + (void)buf_init_chartab(curbuf, FALSE); + parse_cino(curbuf); + } + + // Set/reset the Changed flag first, autocmds may change the buffer. + // Apply the automatic commands, before processing the modelines. + // So the modelines have priority over autocommands. + // + // When reading stdin, the buffer contents always needs writing, so set + // the changed flag. Unless in readonly mode: "ls | gview -". + // When interrupted and 'cpoptions' contains 'i' set changed flag. + if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL) + || modified_was_set // ":set modified" used in autocmd +#ifdef FEAT_EVAL + || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL) +#endif + ) + changed(); + else if (retval == OK && !read_stdin && !read_fifo) + unchanged(curbuf, FALSE, TRUE); + save_file_ff(curbuf); // keep this fileformat + + // Set last_changedtick to avoid triggering a TextChanged autocommand right + // after it was added. + curbuf->b_last_changedtick = CHANGEDTICK(curbuf); + curbuf->b_last_changedtick_i = CHANGEDTICK(curbuf); + curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf); + + // require "!" to overwrite the file, because it wasn't read completely +#ifdef FEAT_EVAL + if (aborting()) +#else + if (got_int) +#endif + curbuf->b_flags |= BF_READERR; + +#ifdef FEAT_FOLDING + // Need to update automatic folding. Do this before the autocommands, + // they may use the fold info. + foldUpdateAll(curwin); +#endif + + // need to set w_topline, unless some autocommand already did that. + if (!(curwin->w_valid & VALID_TOPLINE)) + { + curwin->w_topline = 1; +#ifdef FEAT_DIFF + curwin->w_topfill = 0; +#endif + } +#ifdef FEAT_EVAL + apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, &retval); +#else + apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf); +#endif + + if (retval != OK) + return retval; + + // The autocommands may have changed the current buffer. Apply the + // modelines to the correct buffer, if it still exists and is loaded. + if (bufref_valid(&old_curbuf) && old_curbuf.br_buf->b_ml.ml_mfp != NULL) + { + aco_save_T aco; + + // Go to the buffer that was opened, make sure it is in a window. + // If not then skip it. + aucmd_prepbuf(&aco, old_curbuf.br_buf); + if (curbuf == old_curbuf.br_buf) + { + do_modelines(0); + curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED); + + if ((flags & READ_NOWINENTER) == 0) +#ifdef FEAT_EVAL + apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, + FALSE, curbuf, &retval); +#else + apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, + FALSE, curbuf); +#endif + + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + } + } + + return retval; +} + +/* + * Store "buf" in "bufref" and set the free count. + */ + void +set_bufref(bufref_T *bufref, buf_T *buf) +{ + bufref->br_buf = buf; + bufref->br_fnum = buf == NULL ? 0 : buf->b_fnum; + bufref->br_buf_free_count = buf_free_count; +} + +/* + * Return TRUE if "bufref->br_buf" points to the same buffer as when + * set_bufref() was called and it is a valid buffer. + * Only goes through the buffer list if buf_free_count changed. + * Also checks if b_fnum is still the same, a :bwipe followed by :new might get + * the same allocated memory, but it's a different buffer. + */ + int +bufref_valid(bufref_T *bufref) +{ + return bufref->br_buf_free_count == buf_free_count + ? TRUE : buf_valid(bufref->br_buf) + && bufref->br_fnum == bufref->br_buf->b_fnum; +} + +/* + * Return TRUE if "buf" points to a valid buffer (in the buffer list). + * This can be slow if there are many buffers, prefer using bufref_valid(). + */ + int +buf_valid(buf_T *buf) +{ + buf_T *bp; + + // Assume that we more often have a recent buffer, start with the last + // one. + FOR_ALL_BUFS_FROM_LAST(bp) + if (bp == buf) + return TRUE; + return FALSE; +} + +/* + * A hash table used to quickly lookup a buffer by its number. + */ +static hashtab_T buf_hashtab; + + static void +buf_hashtab_add(buf_T *buf) +{ + sprintf((char *)buf->b_key, "%x", buf->b_fnum); + if (hash_add(&buf_hashtab, buf->b_key, "create buffer") == FAIL) + emsg(_(e_buffer_cannot_be_registered)); +} + + static void +buf_hashtab_remove(buf_T *buf) +{ + hashitem_T *hi = hash_find(&buf_hashtab, buf->b_key); + + if (!HASHITEM_EMPTY(hi)) + hash_remove(&buf_hashtab, hi, "close buffer"); +} + +/* + * Return TRUE when buffer "buf" can be unloaded. + * Give an error message and return FALSE when the buffer is locked or the + * screen is being redrawn and the buffer is in a window. + */ + static int +can_unload_buffer(buf_T *buf) +{ + int can_unload = !buf->b_locked; + + if (can_unload && updating_screen) + { + win_T *wp; + + FOR_ALL_WINDOWS(wp) + if (wp->w_buffer == buf) + { + can_unload = FALSE; + break; + } + } + if (!can_unload) + { + char_u *fname = buf->b_fname != NULL ? buf->b_fname : buf->b_ffname; + + semsg(_(e_attempt_to_delete_buffer_that_is_in_use_str), + fname != NULL ? fname : (char_u *)"[No Name]"); + } + return can_unload; +} + +/* + * Close the link to a buffer. + * "action" is used when there is no longer a window for the buffer. + * It can be: + * 0 buffer becomes hidden + * DOBUF_UNLOAD buffer is unloaded + * DOBUF_DELETE buffer is unloaded and removed from buffer list + * DOBUF_WIPE buffer is unloaded and really deleted + * DOBUF_WIPE_REUSE idem, and add to buf_reuse list + * When doing all but the first one on the current buffer, the caller should + * get a new buffer very soon! + * + * The 'bufhidden' option can force freeing and deleting. + * + * When "abort_if_last" is TRUE then do not close the buffer if autocommands + * cause there to be only one window with this buffer. e.g. when ":quit" is + * supposed to close the window but autocommands close all other windows. + * + * When "ignore_abort" is TRUE don't abort even when aborting() returns TRUE. + * + * Return TRUE when we got to the end and b_nwindows was decremented. + */ + int +close_buffer( + win_T *win, // if not NULL, set b_last_cursor + buf_T *buf, + int action, + int abort_if_last, + int ignore_abort) +{ + int is_curbuf; + int nwindows; + bufref_T bufref; + int is_curwin = (curwin != NULL && curwin->w_buffer == buf); + win_T *the_curwin = curwin; + tabpage_T *the_curtab = curtab; + int unload_buf = (action != 0); + int wipe_buf = (action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE); + int del_buf = (action == DOBUF_DEL || wipe_buf); + + CHECK_CURBUF; + + // Force unloading or deleting when 'bufhidden' says so. + // The caller must take care of NOT deleting/freeing when 'bufhidden' is + // "hide" (otherwise we could never free or delete a buffer). + if (buf->b_p_bh[0] == 'd') // 'bufhidden' == "delete" + { + del_buf = TRUE; + unload_buf = TRUE; + } + else if (buf->b_p_bh[0] == 'w') // 'bufhidden' == "wipe" + { + del_buf = TRUE; + unload_buf = TRUE; + wipe_buf = TRUE; + } + else if (buf->b_p_bh[0] == 'u') // 'bufhidden' == "unload" + unload_buf = TRUE; + +#ifdef FEAT_TERMINAL + // depending on how we get here b_nwindows may already be zero + if (bt_terminal(buf) && (buf->b_nwindows <= 1 || del_buf)) + { + CHECK_CURBUF; + if (term_job_running(buf->b_term)) + { + if (wipe_buf || unload_buf) + { + if (!can_unload_buffer(buf)) + return FALSE; + + // Wiping out or unloading a terminal buffer kills the job. + free_terminal(buf); + + // A terminal buffer is wiped out when job has finished. + del_buf = TRUE; + unload_buf = TRUE; + wipe_buf = TRUE; + } + else + { + // The job keeps running, hide the buffer. + del_buf = FALSE; + unload_buf = FALSE; + } + } + else if (buf->b_p_bh[0] == 'h' && !del_buf) + { + // Hide a terminal buffer. + unload_buf = FALSE; + } + else + { + if (del_buf || unload_buf) + { + // A terminal buffer is wiped out if the job has finished. + // We only do this when there's an intention to unload the + // buffer. This way, :hide and other similar commands won't + // wipe the buffer. + del_buf = TRUE; + unload_buf = TRUE; + wipe_buf = TRUE; + } + } + CHECK_CURBUF; + } +#endif + + // Disallow deleting the buffer when it is locked (already being closed or + // halfway a command that relies on it). Unloading is allowed. + if ((del_buf || wipe_buf) && !can_unload_buffer(buf)) + return FALSE; + + // check no autocommands closed the window + if (win != NULL && win_valid_any_tab(win)) + { + // Set b_last_cursor when closing the last window for the buffer. + // Remember the last cursor position and window options of the buffer. + // This used to be only for the current window, but then options like + // 'foldmethod' may be lost with a ":only" command. + if (buf->b_nwindows == 1) + set_last_cursor(win); + buflist_setfpos(buf, win, + win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum, + win->w_cursor.col, TRUE); + } + + set_bufref(&bufref, buf); + + // When the buffer is no longer in a window, trigger BufWinLeave + if (buf->b_nwindows == 1) + { + ++buf->b_locked; + ++buf->b_locked_split; + if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, + FALSE, buf) + && !bufref_valid(&bufref)) + { + // Autocommands deleted the buffer. +aucmd_abort: + emsg(_(e_autocommands_caused_command_to_abort)); + return FALSE; + } + --buf->b_locked; + --buf->b_locked_split; + if (abort_if_last && one_window()) + // Autocommands made this the only window. + goto aucmd_abort; + + // When the buffer becomes hidden, but is not unloaded, trigger + // BufHidden + if (!unload_buf) + { + ++buf->b_locked; + ++buf->b_locked_split; + if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, + FALSE, buf) + && !bufref_valid(&bufref)) + // Autocommands deleted the buffer. + goto aucmd_abort; + --buf->b_locked; + --buf->b_locked_split; + if (abort_if_last && one_window()) + // Autocommands made this the only window. + goto aucmd_abort; + } +#ifdef FEAT_EVAL + // autocmds may abort script processing + if (!ignore_abort && aborting()) + return FALSE; +#endif + } + + // If the buffer was in curwin and the window has changed, go back to that + // window, if it still exists. This avoids that ":edit x" triggering a + // "tabnext" BufUnload autocmd leaves a window behind without a buffer. + if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin)) + { + block_autocmds(); + goto_tabpage_win(the_curtab, the_curwin); + unblock_autocmds(); + } + + nwindows = buf->b_nwindows; + + // decrease the link count from windows (unless not in any window) + if (buf->b_nwindows > 0) + --buf->b_nwindows; + +#ifdef FEAT_DIFF + if (diffopt_hiddenoff() && !unload_buf && buf->b_nwindows == 0) + diff_buf_delete(buf); // Clear 'diff' for hidden buffer. +#endif + + // Return when a window is displaying the buffer or when it's not + // unloaded. + if (buf->b_nwindows > 0 || !unload_buf) + return FALSE; + + // Always remove the buffer when there is no file name. + if (buf->b_ffname == NULL) + del_buf = TRUE; + + // When closing the current buffer stop Visual mode before freeing + // anything. + if (buf == curbuf && VIsual_active +#if defined(EXITFREE) + && !entered_free_all_mem +#endif + ) + end_visual_mode(); + + // Free all things allocated for this buffer. + // Also calls the "BufDelete" autocommands when del_buf is TRUE. + // + // Remember if we are closing the current buffer. Restore the number of + // windows, so that autocommands in buf_freeall() don't get confused. + is_curbuf = (buf == curbuf); + buf->b_nwindows = nwindows; + + buf_freeall(buf, (del_buf ? BFA_DEL : 0) + + (wipe_buf ? BFA_WIPE : 0) + + (ignore_abort ? BFA_IGNORE_ABORT : 0)); + + // Autocommands may have deleted the buffer. + if (!bufref_valid(&bufref)) + return FALSE; +#ifdef FEAT_EVAL + // autocmds may abort script processing + if (!ignore_abort && aborting()) + return FALSE; +#endif + + // It's possible that autocommands change curbuf to the one being deleted. + // This might cause the previous curbuf to be deleted unexpectedly. But + // in some cases it's OK to delete the curbuf, because a new one is + // obtained anyway. Therefore only return if curbuf changed to the + // deleted buffer. + if (buf == curbuf && !is_curbuf) + return FALSE; + + if (win_valid_any_tab(win) && win->w_buffer == buf) + win->w_buffer = NULL; // make sure we don't use the buffer now + + // Autocommands may have opened or closed windows for this buffer. + // Decrement the count for the close we do here. + if (buf->b_nwindows > 0) + --buf->b_nwindows; + + /* + * Remove the buffer from the list. + */ + if (wipe_buf) + { + // Do not wipe out the buffer if it is used in a window. + if (buf->b_nwindows > 0) + return FALSE; + + if (action == DOBUF_WIPE_REUSE) + { + // we can re-use this buffer number, store it + if (buf_reuse.ga_itemsize == 0) + ga_init2(&buf_reuse, sizeof(int), 50); + if (ga_grow(&buf_reuse, 1) == OK) + ((int *)buf_reuse.ga_data)[buf_reuse.ga_len++] = buf->b_fnum; + } + if (buf->b_sfname != buf->b_ffname) + VIM_CLEAR(buf->b_sfname); + else + buf->b_sfname = NULL; + VIM_CLEAR(buf->b_ffname); + if (buf->b_prev == NULL) + firstbuf = buf->b_next; + else + buf->b_prev->b_next = buf->b_next; + if (buf->b_next == NULL) + lastbuf = buf->b_prev; + else + buf->b_next->b_prev = buf->b_prev; + free_buffer(buf); + } + else + { + if (del_buf) + { + // Free all internal variables and reset option values, to make + // ":bdel" compatible with Vim 5.7. + free_buffer_stuff(buf, TRUE); + + // Make it look like a new buffer. + buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED; + + // Init the options when loaded again. + buf->b_p_initialized = FALSE; + } + buf_clear_file(buf); + if (del_buf) + buf->b_p_bl = FALSE; + } + // NOTE: at this point "curbuf" may be invalid! + return TRUE; +} + +/* + * Make buffer not contain a file. + */ + void +buf_clear_file(buf_T *buf) +{ + buf->b_ml.ml_line_count = 1; + unchanged(buf, TRUE, TRUE); + buf->b_shortname = FALSE; + buf->b_p_eof = FALSE; + buf->b_start_eof = FALSE; + buf->b_p_eol = TRUE; + buf->b_start_eol = TRUE; + buf->b_p_bomb = FALSE; + buf->b_start_bomb = FALSE; + buf->b_ml.ml_mfp = NULL; + buf->b_ml.ml_flags = ML_EMPTY; // empty buffer +#ifdef FEAT_NETBEANS_INTG + netbeans_deleted_all_lines(buf); +#endif +} + +/* + * buf_freeall() - free all things allocated for a buffer that are related to + * the file. Careful: get here with "curwin" NULL when exiting. + * flags: + * BFA_DEL buffer is going to be deleted + * BFA_WIPE buffer is going to be wiped out + * BFA_KEEP_UNDO do not free undo information + * BFA_IGNORE_ABORT don't abort even when aborting() returns TRUE + */ + void +buf_freeall(buf_T *buf, int flags) +{ + int is_curbuf = (buf == curbuf); + bufref_T bufref; + int is_curwin = (curwin != NULL && curwin->w_buffer == buf); + win_T *the_curwin = curwin; + tabpage_T *the_curtab = curtab; + + // Make sure the buffer isn't closed by autocommands. + ++buf->b_locked; + ++buf->b_locked_split; + set_bufref(&bufref, buf); + if (buf->b_ml.ml_mfp != NULL) + { + if (apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, + FALSE, buf) + && !bufref_valid(&bufref)) + // autocommands deleted the buffer + return; + } + if ((flags & BFA_DEL) && buf->b_p_bl) + { + if (apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname, + FALSE, buf) + && !bufref_valid(&bufref)) + // autocommands deleted the buffer + return; + } + if (flags & BFA_WIPE) + { + if (apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname, + FALSE, buf) + && !bufref_valid(&bufref)) + // autocommands deleted the buffer + return; + } + --buf->b_locked; + --buf->b_locked_split; + + // If the buffer was in curwin and the window has changed, go back to that + // window, if it still exists. This avoids that ":edit x" triggering a + // "tabnext" BufUnload autocmd leaves a window behind without a buffer. + if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin)) + { + block_autocmds(); + goto_tabpage_win(the_curtab, the_curwin); + unblock_autocmds(); + } + +#ifdef FEAT_EVAL + // autocmds may abort script processing + if ((flags & BFA_IGNORE_ABORT) == 0 && aborting()) + return; +#endif + + // It's possible that autocommands change curbuf to the one being deleted. + // This might cause curbuf to be deleted unexpectedly. But in some cases + // it's OK to delete the curbuf, because a new one is obtained anyway. + // Therefore only return if curbuf changed to the deleted buffer. + if (buf == curbuf && !is_curbuf) + return; +#ifdef FEAT_DIFF + diff_buf_delete(buf); // Can't use 'diff' for unloaded buffer. +#endif +#ifdef FEAT_SYN_HL + // Remove any ownsyntax, unless exiting. + if (curwin != NULL && curwin->w_buffer == buf) + reset_synblock(curwin); +#endif + +#ifdef FEAT_FOLDING + // No folds in an empty buffer. + { + win_T *win; + tabpage_T *tp; + + FOR_ALL_TAB_WINDOWS(tp, win) + if (win->w_buffer == buf) + clearFolding(win); + } +#endif + +#ifdef FEAT_TCL + tcl_buffer_free(buf); +#endif + ml_close(buf, TRUE); // close and delete the memline/memfile + buf->b_ml.ml_line_count = 0; // no lines in buffer + if ((flags & BFA_KEEP_UNDO) == 0) + { + u_blockfree(buf); // free the memory allocated for undo + u_clearall(buf); // reset all undo information + } +#ifdef FEAT_SYN_HL + syntax_clear(&buf->b_s); // reset syntax info +#endif +#ifdef FEAT_PROP_POPUP + clear_buf_prop_types(buf); +#endif + buf->b_flags &= ~BF_READERR; // a read error is no longer relevant +} + +/* + * Free a buffer structure and the things it contains related to the buffer + * itself (not the file, that must have been done already). + */ + static void +free_buffer(buf_T *buf) +{ + ++buf_free_count; + free_buffer_stuff(buf, TRUE); +#ifdef FEAT_EVAL + // b:changedtick uses an item in buf_T, remove it now + dictitem_remove(buf->b_vars, (dictitem_T *)&buf->b_ct_di, "free buffer"); + unref_var_dict(buf->b_vars); + remove_listeners(buf); +#endif +#ifdef FEAT_LUA + lua_buffer_free(buf); +#endif +#ifdef FEAT_MZSCHEME + mzscheme_buffer_free(buf); +#endif +#ifdef FEAT_PERL + perl_buf_free(buf); +#endif +#ifdef FEAT_PYTHON + python_buffer_free(buf); +#endif +#ifdef FEAT_PYTHON3 + python3_buffer_free(buf); +#endif +#ifdef FEAT_RUBY + ruby_buffer_free(buf); +#endif +#ifdef FEAT_JOB_CHANNEL + channel_buffer_free(buf); +#endif +#ifdef FEAT_TERMINAL + free_terminal(buf); +#endif +#ifdef FEAT_JOB_CHANNEL + vim_free(buf->b_prompt_text); + free_callback(&buf->b_prompt_callback); + free_callback(&buf->b_prompt_interrupt); +#endif + + buf_hashtab_remove(buf); + + aubuflocal_remove(buf); + + if (autocmd_busy) + { + // Do not free the buffer structure while autocommands are executing, + // it's still needed. Free it when autocmd_busy is reset. + buf->b_next = au_pending_free_buf; + au_pending_free_buf = buf; + } + else + { + vim_free(buf); + if (curbuf == buf) + curbuf = NULL; // make clear it's not to be used + } +} + +/* + * Initializes b:changedtick. + */ + static void +init_changedtick(buf_T *buf) +{ + dictitem_T *di = (dictitem_T *)&buf->b_ct_di; + + di->di_flags = DI_FLAGS_FIX | DI_FLAGS_RO; + di->di_tv.v_type = VAR_NUMBER; + di->di_tv.v_lock = VAR_FIXED; + di->di_tv.vval.v_number = 0; + +#ifdef FEAT_EVAL + STRCPY(buf->b_ct_di.di_key, "changedtick"); + (void)dict_add(buf->b_vars, di); +#endif +} + +/* + * Free the b_wininfo list for buffer "buf". + */ + static void +clear_wininfo(buf_T *buf) +{ + wininfo_T *wip; + + while (buf->b_wininfo != NULL) + { + wip = buf->b_wininfo; + buf->b_wininfo = wip->wi_next; + free_wininfo(wip); + } +} + +/* + * Free stuff in the buffer for ":bdel" and when wiping out the buffer. + */ + static void +free_buffer_stuff( + buf_T *buf, + int free_options) // free options as well +{ + if (free_options) + { + clear_wininfo(buf); // including window-local options + free_buf_options(buf, TRUE); +#ifdef FEAT_SPELL + ga_clear(&buf->b_s.b_langp); +#endif + } +#ifdef FEAT_EVAL + { + varnumber_T tick = CHANGEDTICK(buf); + + vars_clear(&buf->b_vars->dv_hashtab); // free all buffer variables + hash_init(&buf->b_vars->dv_hashtab); + init_changedtick(buf); + CHANGEDTICK(buf) = tick; + remove_listeners(buf); + } +#endif + uc_clear(&buf->b_ucmds); // clear local user commands +#ifdef FEAT_SIGNS + buf_delete_signs(buf, (char_u *)"*"); // delete any signs +#endif +#ifdef FEAT_NETBEANS_INTG + netbeans_file_killed(buf); +#endif +#ifdef FEAT_PROP_POPUP + ga_clear_strings(&buf->b_textprop_text); +#endif + map_clear_mode(buf, MAP_ALL_MODES, TRUE, FALSE); // clear local mappings + map_clear_mode(buf, MAP_ALL_MODES, TRUE, TRUE); // clear local abbrevs + VIM_CLEAR(buf->b_start_fenc); +} + +/* + * Free one wininfo_T. + */ + void +free_wininfo(wininfo_T *wip) +{ + if (wip->wi_optset) + { + clear_winopt(&wip->wi_opt); +#ifdef FEAT_FOLDING + deleteFoldRecurse(&wip->wi_folds); +#endif + } + vim_free(wip); +} + +/* + * Go to another buffer. Handles the result of the ATTENTION dialog. + */ + void +goto_buffer( + exarg_T *eap, + int start, + int dir, + int count) +{ + bufref_T old_curbuf; + int save_sea = swap_exists_action; + + set_bufref(&old_curbuf, curbuf); + + if (swap_exists_action == SEA_NONE) + swap_exists_action = SEA_DIALOG; + (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, + start, dir, count, eap->forceit); + if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') + { +#if defined(FEAT_EVAL) + cleanup_T cs; + + // Reset the error/interrupt/exception state here so that + // aborting() returns FALSE when closing a window. + enter_cleanup(&cs); +#endif + + // Quitting means closing the split window, nothing else. + win_close(curwin, TRUE); + swap_exists_action = save_sea; + swap_exists_did_quit = TRUE; + +#if defined(FEAT_EVAL) + // Restore the error/interrupt/exception state if not discarded by a + // new aborting error, interrupt, or uncaught exception. + leave_cleanup(&cs); +#endif + } + else + handle_swap_exists(&old_curbuf); +} + +/* + * Handle the situation of swap_exists_action being set. + * It is allowed for "old_curbuf" to be NULL or invalid. + */ + void +handle_swap_exists(bufref_T *old_curbuf) +{ +#if defined(FEAT_EVAL) + cleanup_T cs; +#endif +#ifdef FEAT_SYN_HL + long old_tw = curbuf->b_p_tw; +#endif + buf_T *buf; + + if (swap_exists_action == SEA_QUIT) + { +#if defined(FEAT_EVAL) + // Reset the error/interrupt/exception state here so that + // aborting() returns FALSE when closing a buffer. + enter_cleanup(&cs); +#endif + + // User selected Quit at ATTENTION prompt. Go back to previous + // buffer. If that buffer is gone or the same as the current one, + // open a new, empty buffer. + swap_exists_action = SEA_NONE; // don't want it again + swap_exists_did_quit = TRUE; + close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE, FALSE); + if (old_curbuf == NULL || !bufref_valid(old_curbuf) + || old_curbuf->br_buf == curbuf) + { + // Block autocommands here because curwin->w_buffer is NULL. + block_autocmds(); + buf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED); + unblock_autocmds(); + } + else + buf = old_curbuf->br_buf; + if (buf != NULL) + { + int old_msg_silent = msg_silent; + + if (shortmess(SHM_FILEINFO)) + msg_silent = 1; // prevent fileinfo message + enter_buffer(buf); + // restore msg_silent, so that the command line will be shown + msg_silent = old_msg_silent; + +#ifdef FEAT_SYN_HL + if (old_tw != curbuf->b_p_tw) + check_colorcolumn(curwin); +#endif + } + // If "old_curbuf" is NULL we are in big trouble here... + +#if defined(FEAT_EVAL) + // Restore the error/interrupt/exception state if not discarded by a + // new aborting error, interrupt, or uncaught exception. + leave_cleanup(&cs); +#endif + } + else if (swap_exists_action == SEA_RECOVER) + { +#if defined(FEAT_EVAL) + // Reset the error/interrupt/exception state here so that + // aborting() returns FALSE when closing a buffer. + enter_cleanup(&cs); +#endif + + // User selected Recover at ATTENTION prompt. + msg_scroll = TRUE; + ml_recover(FALSE); + msg_puts("\n"); // don't overwrite the last message + cmdline_row = msg_row; + do_modelines(0); + +#if defined(FEAT_EVAL) + // Restore the error/interrupt/exception state if not discarded by a + // new aborting error, interrupt, or uncaught exception. + leave_cleanup(&cs); +#endif + } + swap_exists_action = SEA_NONE; +} + +/* + * Make the current buffer empty. + * Used when it is wiped out and it's the last buffer. + */ + static int +empty_curbuf( + int close_others, + int forceit, + int action) +{ + int retval; + buf_T *buf = curbuf; + bufref_T bufref; + + if (action == DOBUF_UNLOAD) + { + emsg(_(e_cannot_unload_last_buffer)); + return FAIL; + } + + set_bufref(&bufref, buf); + if (close_others) + // Close any other windows on this buffer, then make it empty. + close_windows(buf, TRUE); + + setpcmark(); + retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, + forceit ? ECMD_FORCEIT : 0, curwin); + + // do_ecmd() may create a new buffer, then we have to delete + // the old one. But do_ecmd() may have done that already, check + // if the buffer still exists. + if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0) + close_buffer(NULL, buf, action, FALSE, FALSE); + if (!close_others) + need_fileinfo = FALSE; + return retval; +} + +/* + * Implementation of the commands for the buffer list. + * + * action == DOBUF_GOTO go to specified buffer + * action == DOBUF_SPLIT split window and go to specified buffer + * action == DOBUF_UNLOAD unload specified buffer(s) + * action == DOBUF_DEL delete specified buffer(s) from buffer list + * action == DOBUF_WIPE delete specified buffer(s) really + * action == DOBUF_WIPE_REUSE idem, and add number to "buf_reuse" + * + * start == DOBUF_CURRENT go to "count" buffer from current buffer + * start == DOBUF_FIRST go to "count" buffer from first buffer + * start == DOBUF_LAST go to "count" buffer from last buffer + * start == DOBUF_MOD go to "count" modified buffer from current buffer + * + * Return FAIL or OK. + */ + static int +do_buffer_ext( + int action, + int start, + int dir, // FORWARD or BACKWARD + int count, // buffer number or number of buffers + int flags) // DOBUF_FORCEIT etc. +{ + buf_T *buf; + buf_T *bp; + int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL + || action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE); + + switch (start) + { + case DOBUF_FIRST: buf = firstbuf; break; + case DOBUF_LAST: buf = lastbuf; break; + default: buf = curbuf; break; + } + if (start == DOBUF_MOD) // find next modified buffer + { + while (count-- > 0) + { + do + { + buf = buf->b_next; + if (buf == NULL) + buf = firstbuf; + } + while (buf != curbuf && !bufIsChanged(buf)); + } + if (!bufIsChanged(buf)) + { + emsg(_(e_no_modified_buffer_found)); + return FAIL; + } + } + else if (start == DOBUF_FIRST && count) // find specified buffer number + { + while (buf != NULL && buf->b_fnum != count) + buf = buf->b_next; + } + else + { + bp = NULL; + while (count > 0 || (!unload && !buf->b_p_bl && bp != buf)) + { + // remember the buffer where we start, we come back there when all + // buffers are unlisted. + if (bp == NULL) + bp = buf; + if (dir == FORWARD) + { + buf = buf->b_next; + if (buf == NULL) + buf = firstbuf; + } + else + { + buf = buf->b_prev; + if (buf == NULL) + buf = lastbuf; + } + // don't count unlisted buffers + if (unload || buf->b_p_bl) + { + --count; + bp = NULL; // use this buffer as new starting point + } + if (bp == buf) + { + // back where we started, didn't find anything. + emsg(_(e_there_is_no_listed_buffer)); + return FAIL; + } + } + } + + if (buf == NULL) // could not find it + { + if (start == DOBUF_FIRST) + { + // don't warn when deleting + if (!unload) + semsg(_(e_buffer_nr_does_not_exist), count); + } + else if (dir == FORWARD) + emsg(_(e_cannot_go_beyond_last_buffer)); + else + emsg(_(e_cannot_go_before_first_buffer)); + return FAIL; + } +#ifdef FEAT_PROP_POPUP + if ((flags & DOBUF_NOPOPUP) && bt_popup(buf) && !bt_terminal(buf)) + return OK; +#endif + if ((action == DOBUF_GOTO || action == DOBUF_SPLIT) + && (buf->b_flags & BF_DUMMY)) + { + // disallow navigating to the dummy buffer + semsg(_(e_buffer_nr_does_not_exist), count); + return FAIL; + } + +#ifdef FEAT_GUI + need_mouse_correct = TRUE; +#endif + + /* + * delete buffer "buf" from memory and/or the list + */ + if (unload) + { + int forward; + bufref_T bufref; + + if (!can_unload_buffer(buf)) + return FAIL; + + set_bufref(&bufref, buf); + + // When unloading or deleting a buffer that's already unloaded and + // unlisted: fail silently. + if (action != DOBUF_WIPE && action != DOBUF_WIPE_REUSE + && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl) + return FAIL; + + if ((flags & DOBUF_FORCEIT) == 0 && bufIsChanged(buf)) + { +#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) + if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) + { +# ifdef FEAT_TERMINAL + if (term_job_running(buf->b_term)) + { + if (term_confirm_stop(buf) == FAIL) + return FAIL; + } + else +# endif + { + dialog_changed(buf, FALSE); + if (!bufref_valid(&bufref)) + // Autocommand deleted buffer, oops! It's not changed + // now. + return FAIL; + // If it's still changed fail silently, the dialog already + // mentioned why it fails. + if (bufIsChanged(buf)) + return FAIL; + } + } + else +#endif + { + no_write_message_buf(buf); + return FAIL; + } + } + + // When closing the current buffer stop Visual mode. + if (buf == curbuf && VIsual_active) + end_visual_mode(); + + // If deleting the last (listed) buffer, make it empty. + // The last (listed) buffer cannot be unloaded. + FOR_ALL_BUFFERS(bp) + if (bp->b_p_bl && bp != buf) + break; + if (bp == NULL && buf == curbuf) + return empty_curbuf(TRUE, (flags & DOBUF_FORCEIT), action); + + // If the deleted buffer is the current one, close the current window + // (unless it's the only window). Repeat this so long as we end up in + // a window with this buffer. + while (buf == curbuf + && !(curwin->w_closing || curwin->w_buffer->b_locked > 0) + && (!ONE_WINDOW || first_tabpage->tp_next != NULL)) + { + if (win_close(curwin, FALSE) == FAIL) + break; + } + + // If the buffer to be deleted is not the current one, delete it here. + if (buf != curbuf) + { + close_windows(buf, FALSE); + if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows <= 0) + close_buffer(NULL, buf, action, FALSE, FALSE); + return OK; + } + + /* + * Deleting the current buffer: Need to find another buffer to go to. + * There should be another, otherwise it would have been handled + * above. However, autocommands may have deleted all buffers. + * First use au_new_curbuf.br_buf, if it is valid. + * Then prefer the buffer we most recently visited. + * Else try to find one that is loaded, after the current buffer, + * then before the current buffer. + * Finally use any buffer. + */ + buf = NULL; // selected buffer + bp = NULL; // used when no loaded buffer found + if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf)) + buf = au_new_curbuf.br_buf; + else if (curwin->w_jumplistlen > 0) + { + int jumpidx; + + jumpidx = curwin->w_jumplistidx - 1; + if (jumpidx < 0) + jumpidx = curwin->w_jumplistlen - 1; + + forward = jumpidx; + while (jumpidx != curwin->w_jumplistidx) + { + buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum); + if (buf != NULL) + { + // Skip current and unlisted bufs. Also skip a quickfix + // buffer, it might be deleted soon. + if (buf == curbuf || !buf->b_p_bl || bt_quickfix(buf)) + buf = NULL; + else if (buf->b_ml.ml_mfp == NULL) + { + // skip unloaded buf, but may keep it for later + if (bp == NULL) + bp = buf; + buf = NULL; + } + } + if (buf != NULL) // found a valid buffer: stop searching + break; + // advance to older entry in jump list + if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen) + break; + if (--jumpidx < 0) + jumpidx = curwin->w_jumplistlen - 1; + if (jumpidx == forward) // List exhausted for sure + break; + } + } + + if (buf == NULL) // No previous buffer, Try 2'nd approach + { + forward = TRUE; + buf = curbuf->b_next; + for (;;) + { + if (buf == NULL) + { + if (!forward) // tried both directions + break; + buf = curbuf->b_prev; + forward = FALSE; + continue; + } + // in non-help buffer, try to skip help buffers, and vv + if (buf->b_help == curbuf->b_help && buf->b_p_bl + && !bt_quickfix(buf)) + { + if (buf->b_ml.ml_mfp != NULL) // found loaded buffer + break; + if (bp == NULL) // remember unloaded buf for later + bp = buf; + } + if (forward) + buf = buf->b_next; + else + buf = buf->b_prev; + } + } + if (buf == NULL) // No loaded buffer, use unloaded one + buf = bp; + if (buf == NULL) // No loaded buffer, find listed one + { + FOR_ALL_BUFFERS(buf) + if (buf->b_p_bl && buf != curbuf && !bt_quickfix(buf)) + break; + } + if (buf == NULL) // Still no buffer, just take one + { + if (curbuf->b_next != NULL) + buf = curbuf->b_next; + else + buf = curbuf->b_prev; + if (bt_quickfix(buf)) + buf = NULL; + } + } + + if (buf == NULL) + { + // Autocommands must have wiped out all other buffers. Only option + // now is to make the current buffer empty. + return empty_curbuf(FALSE, (flags & DOBUF_FORCEIT), action); + } + + /* + * make "buf" the current buffer + */ + if (action == DOBUF_SPLIT) // split window first + { + // If 'switchbuf' contains "useopen": jump to first window containing + // "buf" if one exists + if ((swb_flags & SWB_USEOPEN) && buf_jump_open_win(buf)) + return OK; + // If 'switchbuf' contains "usetab": jump to first window in any tab + // page containing "buf" if one exists + if ((swb_flags & SWB_USETAB) && buf_jump_open_tab(buf)) + return OK; + if (win_split(0, 0) == FAIL) + return FAIL; + } + + // go to current buffer - nothing to do + if (buf == curbuf) + return OK; + + // Check if the current buffer may be abandoned. + if (action == DOBUF_GOTO && !can_abandon(curbuf, (flags & DOBUF_FORCEIT))) + { +#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) + if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) + { +# ifdef FEAT_TERMINAL + if (term_job_running(curbuf->b_term)) + { + if (term_confirm_stop(curbuf) == FAIL) + return FAIL; + // Manually kill the terminal here because this command will + // hide it otherwise. + free_terminal(curbuf); + } + else +# endif + { + bufref_T bufref; + + set_bufref(&bufref, buf); + dialog_changed(curbuf, FALSE); + if (!bufref_valid(&bufref)) + // Autocommand deleted buffer, oops! + return FAIL; + + if (bufIsChanged(curbuf)) + { + no_write_message(); + return FAIL; + } + } + } + else +#endif + { + no_write_message(); + return FAIL; + } + } + + // Go to the other buffer. + set_curbuf(buf, action); + + if (action == DOBUF_SPLIT) + RESET_BINDING(curwin); // reset 'scrollbind' and 'cursorbind' + +#if defined(FEAT_EVAL) + if (aborting()) // autocmds may abort script processing + return FAIL; +#endif + + return OK; +} + + int +do_buffer( + int action, + int start, + int dir, // FORWARD or BACKWARD + int count, // buffer number or number of buffers + int forceit) // TRUE when using ! +{ + return do_buffer_ext(action, start, dir, count, + forceit ? DOBUF_FORCEIT : 0); +} + +/* + * do_bufdel() - delete or unload buffer(s) + * + * addr_count == 0: ":bdel" - delete current buffer + * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete + * buffer "end_bnr", then any other arguments. + * addr_count == 2: ":N,N bdel" - delete buffers in range + * + * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or + * DOBUF_DEL (":bdel") + * + * Returns error message or NULL + */ + char * +do_bufdel( + int command, + char_u *arg, // pointer to extra arguments + int addr_count, + int start_bnr, // first buffer number in a range + int end_bnr, // buffer nr or last buffer nr in a range + int forceit) +{ + int do_current = 0; // delete current buffer? + int deleted = 0; // number of buffers deleted + char *errormsg = NULL; // return value + int bnr; // buffer number + char_u *p; + + if (addr_count == 0) + { + (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit); + } + else + { + if (addr_count == 2) + { + if (*arg) // both range and argument is not allowed + return ex_errmsg(e_trailing_characters_str, arg); + bnr = start_bnr; + } + else // addr_count == 1 + bnr = end_bnr; + + for ( ;!got_int; ui_breakcheck()) + { + // Delete the current buffer last, otherwise when the + // current buffer is deleted, the next buffer becomes + // the current one and will be loaded, which may then + // also be deleted, etc. + if (bnr == curbuf->b_fnum) + do_current = bnr; + else if (do_buffer_ext(command, DOBUF_FIRST, FORWARD, bnr, + DOBUF_NOPOPUP | (forceit ? DOBUF_FORCEIT : 0)) == OK) + ++deleted; + + // find next buffer number to delete/unload + if (addr_count == 2) + { + if (++bnr > end_bnr) + break; + } + else // addr_count == 1 + { + arg = skipwhite(arg); + if (*arg == NUL) + break; + if (!VIM_ISDIGIT(*arg)) + { + p = skiptowhite_esc(arg); + bnr = buflist_findpat(arg, p, + command == DOBUF_WIPE || command == DOBUF_WIPE_REUSE, + FALSE, FALSE); + if (bnr < 0) // failed + break; + arg = p; + } + else + bnr = getdigits(&arg); + } + } + if (!got_int && do_current && do_buffer(command, DOBUF_FIRST, + FORWARD, do_current, forceit) == OK) + ++deleted; + + if (deleted == 0) + { + if (command == DOBUF_UNLOAD) + STRCPY(IObuff, _(e_no_buffers_were_unloaded)); + else if (command == DOBUF_DEL) + STRCPY(IObuff, _(e_no_buffers_were_deleted)); + else + STRCPY(IObuff, _(e_no_buffers_were_wiped_out)); + errormsg = (char *)IObuff; + } + else if (deleted >= p_report) + { + if (command == DOBUF_UNLOAD) + smsg(NGETTEXT("%d buffer unloaded", + "%d buffers unloaded", deleted), deleted); + else if (command == DOBUF_DEL) + smsg(NGETTEXT("%d buffer deleted", + "%d buffers deleted", deleted), deleted); + else + smsg(NGETTEXT("%d buffer wiped out", + "%d buffers wiped out", deleted), deleted); + } + } + + return errormsg; +} + +/* + * Set current buffer to "buf". Executes autocommands and closes current + * buffer. "action" tells how to close the current buffer: + * DOBUF_GOTO free or hide it + * DOBUF_SPLIT nothing + * DOBUF_UNLOAD unload it + * DOBUF_DEL delete it + * DOBUF_WIPE wipe it out + * DOBUF_WIPE_REUSE wipe it out and add to "buf_reuse" + */ + void +set_curbuf(buf_T *buf, int action) +{ + buf_T *prevbuf; + int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL + || action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE); +#ifdef FEAT_SYN_HL + long old_tw = curbuf->b_p_tw; +#endif + bufref_T newbufref; + bufref_T prevbufref; + int valid; + + setpcmark(); + if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0) + curwin->w_alt_fnum = curbuf->b_fnum; // remember alternate file + buflist_altfpos(curwin); // remember curpos + + // Don't restart Select mode after switching to another buffer. + VIsual_reselect = FALSE; + + // close_windows() or apply_autocmds() may change curbuf and wipe out "buf" + prevbuf = curbuf; + set_bufref(&prevbufref, prevbuf); + set_bufref(&newbufref, buf); + + // Autocommands may delete the current buffer and/or the buffer we want to + // go to. In those cases don't close the buffer. + if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf) + || (bufref_valid(&prevbufref) + && bufref_valid(&newbufref) +#ifdef FEAT_EVAL + && !aborting() +#endif + )) + { +#ifdef FEAT_SYN_HL + if (prevbuf == curwin->w_buffer) + reset_synblock(curwin); +#endif + if (unload) + close_windows(prevbuf, FALSE); +#if defined(FEAT_EVAL) + if (bufref_valid(&prevbufref) && !aborting()) +#else + if (bufref_valid(&prevbufref)) +#endif + { + win_T *previouswin = curwin; + + // Do not sync when in Insert mode and the buffer is open in + // another window, might be a timer doing something in another + // window. + if (prevbuf == curbuf + && ((State & MODE_INSERT) == 0 || curbuf->b_nwindows <= 1)) + u_sync(FALSE); + close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, + unload ? action : (action == DOBUF_GOTO + && !buf_hide(prevbuf) + && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, + FALSE, FALSE); + if (curwin != previouswin && win_valid(previouswin)) + // autocommands changed curwin, Grr! + curwin = previouswin; + } + } + // An autocommand may have deleted "buf", already entered it (e.g., when + // it did ":bunload") or aborted the script processing. + // If curwin->w_buffer is null, enter_buffer() will make it valid again + valid = buf_valid(buf); + if ((valid && buf != curbuf +#ifdef FEAT_EVAL + && !aborting() +#endif + ) || curwin->w_buffer == NULL) + { + // If the buffer is not valid but curwin->w_buffer is NULL we must + // enter some buffer. Using the last one is hopefully OK. + if (!valid) + enter_buffer(lastbuf); + else + enter_buffer(buf); +#ifdef FEAT_SYN_HL + if (old_tw != curbuf->b_p_tw) + check_colorcolumn(curwin); +#endif + } +} + +/* + * Enter a new current buffer. + * Old curbuf must have been abandoned already! This also means "curbuf" may + * be pointing to freed memory. + */ + static void +enter_buffer(buf_T *buf) +{ + // when closing the current buffer stop Visual mode + if (VIsual_active +#if defined(EXITFREE) + && !entered_free_all_mem +#endif + ) + end_visual_mode(); + + // Get the buffer in the current window. + curwin->w_buffer = buf; + curbuf = buf; + ++curbuf->b_nwindows; + + // Copy buffer and window local option values. Not for a help buffer. + buf_copy_options(buf, BCO_ENTER | BCO_NOHELP); + if (!buf->b_help) + get_winopts(buf); +#ifdef FEAT_FOLDING + else + // Remove all folds in the window. + clearFolding(curwin); + foldUpdateAll(curwin); // update folds (later). +#endif + +#ifdef FEAT_DIFF + if (curwin->w_p_diff) + diff_buf_add(curbuf); +#endif + +#ifdef FEAT_SYN_HL + curwin->w_s = &(curbuf->b_s); +#endif + + // Cursor on first line by default. + curwin->w_cursor.lnum = 1; + curwin->w_cursor.col = 0; + curwin->w_cursor.coladd = 0; + curwin->w_set_curswant = TRUE; + curwin->w_topline_was_set = FALSE; + + // mark cursor position as being invalid + curwin->w_valid = 0; + + buflist_setfpos(curbuf, curwin, curbuf->b_last_cursor.lnum, + curbuf->b_last_cursor.col, TRUE); + + // Make sure the buffer is loaded. + if (curbuf->b_ml.ml_mfp == NULL) // need to load the file + { + // If there is no filetype, allow for detecting one. Esp. useful for + // ":ball" used in an autocommand. If there already is a filetype we + // might prefer to keep it. + if (*curbuf->b_p_ft == NUL) + did_filetype = FALSE; + + open_buffer(FALSE, NULL, 0); + } + else + { + if (!msg_silent && !shortmess(SHM_FILEINFO)) + need_fileinfo = TRUE; // display file info after redraw + + // check if file changed + (void)buf_check_timestamp(curbuf, FALSE); + + curwin->w_topline = 1; +#ifdef FEAT_DIFF + curwin->w_topfill = 0; +#endif + apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf); + apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf); + } + + // If autocommands did not change the cursor position, restore cursor lnum + // and possibly cursor col. + if (curwin->w_cursor.lnum == 1 && inindent(0)) + buflist_getfpos(); + + check_arg_idx(curwin); // check for valid arg_idx + maketitle(); + // when autocmds didn't change it + if (curwin->w_topline == 1 && !curwin->w_topline_was_set) + scroll_cursor_halfway(FALSE, FALSE); // redisplay at correct position + +#ifdef FEAT_NETBEANS_INTG + // Send fileOpened event because we've changed buffers. + netbeans_file_activated(curbuf); +#endif + + // Change directories when the 'acd' option is set. + DO_AUTOCHDIR; + +#ifdef FEAT_KEYMAP + if (curbuf->b_kmap_state & KEYMAP_INIT) + (void)keymap_init(); +#endif +#ifdef FEAT_SPELL + // May need to set the spell language. Can only do this after the buffer + // has been properly setup. + if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) + (void)parse_spelllang(curwin); +#endif +#ifdef FEAT_VIMINFO + curbuf->b_last_used = vim_time(); +#endif + + redraw_later(UPD_NOT_VALID); +} + +#if defined(FEAT_AUTOCHDIR) || defined(PROTO) +/* + * Change to the directory of the current buffer. + * Don't do this while still starting up. + */ + void +do_autochdir(void) +{ + if ((starting == 0 || test_autochdir) + && curbuf->b_ffname != NULL + && vim_chdirfile(curbuf->b_ffname, "auto") == OK) + { + shorten_fnames(TRUE); + last_chdir_reason = "autochdir"; + } +} +#endif + + static void +no_write_message_buf(buf_T *buf UNUSED) +{ +#ifdef FEAT_TERMINAL + if (term_job_running(buf->b_term)) + emsg(_(e_job_still_running_add_bang_to_end_the_job)); + else +#endif + semsg(_(e_no_write_since_last_change_for_buffer_nr_add_bang_to_override), + buf->b_fnum); +} + + void +no_write_message(void) +{ +#ifdef FEAT_TERMINAL + if (term_job_running(curbuf->b_term)) + emsg(_(e_job_still_running_add_bang_to_end_the_job)); + else +#endif + emsg(_(e_no_write_since_last_change_add_bang_to_override)); +} + + void +no_write_message_nobang(buf_T *buf UNUSED) +{ +#ifdef FEAT_TERMINAL + if (term_job_running(buf->b_term)) + emsg(_(e_job_still_running)); + else +#endif + emsg(_(e_no_write_since_last_change)); +} + +/* + * functions for dealing with the buffer list + */ + +/* + * Return TRUE if the current buffer is empty, unnamed, unmodified and used in + * only one window. That means it can be re-used. + */ + int +curbuf_reusable(void) +{ + return (curbuf != NULL + && curbuf->b_ffname == NULL + && curbuf->b_nwindows <= 1 + && (curbuf->b_ml.ml_mfp == NULL || BUFEMPTY()) + && !bt_quickfix(curbuf) + && !curbufIsChanged()); +} + +/* + * Add a file name to the buffer list. Return a pointer to the buffer. + * If the same file name already exists return a pointer to that buffer. + * If it does not exist, or if fname == NULL, a new entry is created. + * If (flags & BLN_CURBUF) is TRUE, may use current buffer. + * If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list. + * If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer. + * If (flags & BLN_NEW) is TRUE, don't use an existing buffer. + * If (flags & BLN_NOOPT) is TRUE, don't copy options from the current buffer + * if the buffer already exists. + * If (flags & BLN_REUSE) is TRUE, may use buffer number from "buf_reuse". + * This is the ONLY way to create a new buffer. + */ + buf_T * +buflist_new( + char_u *ffname_arg, // full path of fname or relative + char_u *sfname_arg, // short fname or NULL + linenr_T lnum, // preferred cursor line + int flags) // BLN_ defines +{ + char_u *ffname = ffname_arg; + char_u *sfname = sfname_arg; + buf_T *buf; +#ifdef UNIX + stat_T st; +#endif + + if (top_file_num == 1) + hash_init(&buf_hashtab); + + fname_expand(curbuf, &ffname, &sfname); // will allocate ffname + + /* + * If the file name already exists in the list, update the entry. + */ +#ifdef UNIX + // On Unix we can use inode numbers when the file exists. Works better + // for hard links. + if (sfname == NULL || mch_stat((char *)sfname, &st) < 0) + st.st_dev = (dev_T)-1; +#endif + if (ffname != NULL && !(flags & (BLN_DUMMY | BLN_NEW)) && (buf = +#ifdef UNIX + buflist_findname_stat(ffname, &st) +#else + buflist_findname(ffname) +#endif + ) != NULL) + { + vim_free(ffname); + if (lnum != 0) + buflist_setfpos(buf, (flags & BLN_NOCURWIN) ? NULL : curwin, + lnum, (colnr_T)0, FALSE); + + if ((flags & BLN_NOOPT) == 0) + // copy the options now, if 'cpo' doesn't have 's' and not done + // already + buf_copy_options(buf, 0); + + if ((flags & BLN_LISTED) && !buf->b_p_bl) + { + bufref_T bufref; + + buf->b_p_bl = TRUE; + set_bufref(&bufref, buf); + if (!(flags & BLN_DUMMY)) + { + if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf) + && !bufref_valid(&bufref)) + return NULL; + } + } + return buf; + } + + /* + * If the current buffer has no name and no contents, use the current + * buffer. Otherwise: Need to allocate a new buffer structure. + * + * This is the ONLY place where a new buffer structure is allocated! + * (A spell file buffer is allocated in spell.c, but that's not a normal + * buffer.) + */ + buf = NULL; + if ((flags & BLN_CURBUF) && curbuf_reusable()) + { + buf = curbuf; + // It's like this buffer is deleted. Watch out for autocommands that + // change curbuf! If that happens, allocate a new buffer anyway. + buf_freeall(buf, BFA_WIPE | BFA_DEL); + if (buf != curbuf) // autocommands deleted the buffer! + return NULL; +#ifdef FEAT_EVAL + if (aborting()) // autocmds may abort script processing + { + vim_free(ffname); + return NULL; + } +#endif + } + if (buf != curbuf || curbuf == NULL) + { + buf = ALLOC_CLEAR_ONE(buf_T); + if (buf == NULL) + { + vim_free(ffname); + return NULL; + } +#ifdef FEAT_EVAL + // init b: variables + buf->b_vars = dict_alloc_id(aid_newbuf_bvars); + if (buf->b_vars == NULL) + { + vim_free(ffname); + vim_free(buf); + return NULL; + } + init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE); +#endif + init_changedtick(buf); + } + + if (ffname != NULL) + { + buf->b_ffname = ffname; + buf->b_sfname = vim_strsave(sfname); + } + + clear_wininfo(buf); + buf->b_wininfo = ALLOC_CLEAR_ONE(wininfo_T); + + if ((ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL)) + || buf->b_wininfo == NULL) + { + if (buf->b_sfname != buf->b_ffname) + VIM_CLEAR(buf->b_sfname); + else + buf->b_sfname = NULL; + VIM_CLEAR(buf->b_ffname); + if (buf != curbuf) + free_buffer(buf); + return NULL; + } + + if (buf == curbuf) + { + free_buffer_stuff(buf, FALSE); // delete local variables et al. + + // Init the options. + buf->b_p_initialized = FALSE; + buf_copy_options(buf, BCO_ENTER); + +#ifdef FEAT_KEYMAP + // need to reload lmaps and set b:keymap_name + curbuf->b_kmap_state |= KEYMAP_INIT; +#endif + } + else + { + // put the new buffer at the end of the buffer list + buf->b_next = NULL; + if (firstbuf == NULL) // buffer list is empty + { + buf->b_prev = NULL; + firstbuf = buf; + } + else // append new buffer at end of list + { + lastbuf->b_next = buf; + buf->b_prev = lastbuf; + } + lastbuf = buf; + + if ((flags & BLN_REUSE) && buf_reuse.ga_len > 0) + { + // Recycle a previously used buffer number. Used for buffers which + // are normally hidden, e.g. in a popup window. Avoids that the + // buffer number grows rapidly. + --buf_reuse.ga_len; + buf->b_fnum = ((int *)buf_reuse.ga_data)[buf_reuse.ga_len]; + + // Move buffer to the right place in the buffer list. + while (buf->b_prev != NULL && buf->b_fnum < buf->b_prev->b_fnum) + { + buf_T *prev = buf->b_prev; + + prev->b_next = buf->b_next; + if (prev->b_next != NULL) + prev->b_next->b_prev = prev; + buf->b_next = prev; + buf->b_prev = prev->b_prev; + if (buf->b_prev != NULL) + buf->b_prev->b_next = buf; + prev->b_prev = buf; + if (lastbuf == buf) + lastbuf = prev; + if (firstbuf == prev) + firstbuf = buf; + } + } + else + buf->b_fnum = top_file_num++; + if (top_file_num < 0) // wrap around (may cause duplicates) + { + emsg(_("W14: Warning: List of file names overflow")); + if (emsg_silent == 0 && !in_assert_fails) + { + out_flush(); + ui_delay(3001L, TRUE); // make sure it is noticed + } + top_file_num = 1; + } + buf_hashtab_add(buf); + + // Always copy the options from the current buffer. + buf_copy_options(buf, BCO_ALWAYS); + } + + buf->b_wininfo->wi_fpos.lnum = lnum; + buf->b_wininfo->wi_win = curwin; + +#ifdef FEAT_SYN_HL + hash_init(&buf->b_s.b_keywtab); + hash_init(&buf->b_s.b_keywtab_ic); +#endif + + buf->b_fname = buf->b_sfname; +#ifdef UNIX + if (st.st_dev == (dev_T)-1) + buf->b_dev_valid = FALSE; + else + { + buf->b_dev_valid = TRUE; + buf->b_dev = st.st_dev; + buf->b_ino = st.st_ino; + } +#endif + buf->b_u_synced = TRUE; + buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED; + if (flags & BLN_DUMMY) + buf->b_flags |= BF_DUMMY; + buf_clear_file(buf); + clrallmarks(buf); // clear marks + fmarks_check_names(buf); // check file marks for this file + buf->b_p_bl = (flags & BLN_LISTED) ? TRUE : FALSE; // init 'buflisted' + if (!(flags & BLN_DUMMY)) + { + bufref_T bufref; + + // Tricky: these autocommands may change the buffer list. They could + // also split the window with re-using the one empty buffer. This may + // result in unexpectedly losing the empty buffer. + set_bufref(&bufref, buf); + if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf) + && !bufref_valid(&bufref)) + return NULL; + if (flags & BLN_LISTED) + { + if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf) + && !bufref_valid(&bufref)) + return NULL; + } +#ifdef FEAT_EVAL + if (aborting()) // autocmds may abort script processing + return NULL; +#endif + } + + return buf; +} + +/* + * Free the memory for the options of a buffer. + * If "free_p_ff" is TRUE also free 'fileformat', 'buftype' and + * 'fileencoding'. + */ + void +free_buf_options( + buf_T *buf, + int free_p_ff) +{ + if (free_p_ff) + { + clear_string_option(&buf->b_p_fenc); + clear_string_option(&buf->b_p_ff); + clear_string_option(&buf->b_p_bh); + clear_string_option(&buf->b_p_bt); + } +#ifdef FEAT_FIND_ID + clear_string_option(&buf->b_p_def); + clear_string_option(&buf->b_p_inc); +# ifdef FEAT_EVAL + clear_string_option(&buf->b_p_inex); +# endif +#endif +#if defined(FEAT_EVAL) + clear_string_option(&buf->b_p_inde); + clear_string_option(&buf->b_p_indk); +#endif +#if defined(FEAT_BEVAL) && defined(FEAT_EVAL) + clear_string_option(&buf->b_p_bexpr); +#endif +#if defined(FEAT_CRYPT) + clear_string_option(&buf->b_p_cm); +#endif + clear_string_option(&buf->b_p_fp); +#if defined(FEAT_EVAL) + clear_string_option(&buf->b_p_fex); +#endif +#ifdef FEAT_CRYPT +# ifdef FEAT_SODIUM + if ((buf->b_p_key != NULL) && (*buf->b_p_key != NUL) && + (crypt_get_method_nr(buf) == CRYPT_M_SOD)) + crypt_sodium_munlock(buf->b_p_key, STRLEN(buf->b_p_key)); +# endif + clear_string_option(&buf->b_p_key); +#endif + clear_string_option(&buf->b_p_kp); + clear_string_option(&buf->b_p_mps); + clear_string_option(&buf->b_p_fo); + clear_string_option(&buf->b_p_flp); + clear_string_option(&buf->b_p_isk); +#ifdef FEAT_VARTABS + clear_string_option(&buf->b_p_vsts); + vim_free(buf->b_p_vsts_nopaste); + buf->b_p_vsts_nopaste = NULL; + VIM_CLEAR(buf->b_p_vsts_array); + clear_string_option(&buf->b_p_vts); + VIM_CLEAR(buf->b_p_vts_array); +#endif +#ifdef FEAT_KEYMAP + clear_string_option(&buf->b_p_keymap); + keymap_clear(&buf->b_kmap_ga); + ga_clear(&buf->b_kmap_ga); +#endif + clear_string_option(&buf->b_p_com); +#ifdef FEAT_FOLDING + clear_string_option(&buf->b_p_cms); +#endif + clear_string_option(&buf->b_p_nf); +#ifdef FEAT_SYN_HL + clear_string_option(&buf->b_p_syn); + clear_string_option(&buf->b_s.b_syn_isk); +#endif +#ifdef FEAT_SPELL + clear_string_option(&buf->b_s.b_p_spc); + clear_string_option(&buf->b_s.b_p_spf); + vim_regfree(buf->b_s.b_cap_prog); + buf->b_s.b_cap_prog = NULL; + clear_string_option(&buf->b_s.b_p_spl); + clear_string_option(&buf->b_s.b_p_spo); +#endif + clear_string_option(&buf->b_p_sua); + clear_string_option(&buf->b_p_ft); + clear_string_option(&buf->b_p_cink); + clear_string_option(&buf->b_p_cino); + clear_string_option(&buf->b_p_lop); + clear_string_option(&buf->b_p_cinsd); + clear_string_option(&buf->b_p_cinw); + clear_string_option(&buf->b_p_cpt); +#ifdef FEAT_COMPL_FUNC + clear_string_option(&buf->b_p_cfu); + free_callback(&buf->b_cfu_cb); + clear_string_option(&buf->b_p_ofu); + free_callback(&buf->b_ofu_cb); + clear_string_option(&buf->b_p_tsrfu); + free_callback(&buf->b_tsrfu_cb); +#endif +#ifdef FEAT_QUICKFIX + clear_string_option(&buf->b_p_gp); + clear_string_option(&buf->b_p_mp); + clear_string_option(&buf->b_p_efm); +#endif + clear_string_option(&buf->b_p_ep); + clear_string_option(&buf->b_p_path); + clear_string_option(&buf->b_p_tags); + clear_string_option(&buf->b_p_tc); +#ifdef FEAT_EVAL + clear_string_option(&buf->b_p_tfu); + free_callback(&buf->b_tfu_cb); +#endif + clear_string_option(&buf->b_p_dict); + clear_string_option(&buf->b_p_tsr); + clear_string_option(&buf->b_p_qe); + buf->b_p_ar = -1; + buf->b_p_ul = NO_LOCAL_UNDOLEVEL; + clear_string_option(&buf->b_p_lw); + clear_string_option(&buf->b_p_bkc); + clear_string_option(&buf->b_p_menc); +} + +/* + * Get alternate file "n". + * Set linenr to "lnum" or altfpos.lnum if "lnum" == 0. + * Also set cursor column to altfpos.col if 'startofline' is not set. + * if (options & GETF_SETMARK) call setpcmark() + * if (options & GETF_ALT) we are jumping to an alternate file. + * if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping + * + * Return FAIL for failure, OK for success. + */ + int +buflist_getfile( + int n, + linenr_T lnum, + int options, + int forceit) +{ + buf_T *buf; + win_T *wp = NULL; + pos_T *fpos; + colnr_T col; + + buf = buflist_findnr(n); + if (buf == NULL) + { + if ((options & GETF_ALT) && n == 0) + emsg(_(e_no_alternate_file)); + else + semsg(_(e_buffer_nr_not_found), n); + return FAIL; + } + + // if alternate file is the current buffer, nothing to do + if (buf == curbuf) + return OK; + + if (text_or_buf_locked()) + return FAIL; + + // altfpos may be changed by getfile(), get it now + if (lnum == 0) + { + fpos = buflist_findfpos(buf); + lnum = fpos->lnum; + col = fpos->col; + } + else + col = 0; + + if (options & GETF_SWITCH) + { + // If 'switchbuf' contains "useopen": jump to first window containing + // "buf" if one exists + if (swb_flags & SWB_USEOPEN) + wp = buf_jump_open_win(buf); + + // If 'switchbuf' contains "usetab": jump to first window in any tab + // page containing "buf" if one exists + if (wp == NULL && (swb_flags & SWB_USETAB)) + wp = buf_jump_open_tab(buf); + + // If 'switchbuf' contains "split", "vsplit" or "newtab" and the + // current buffer isn't empty: open new tab or window + if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB)) + && !BUFEMPTY()) + { + if (swb_flags & SWB_NEWTAB) + tabpage_new(); + else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0) + == FAIL) + return FAIL; + RESET_BINDING(curwin); + } + } + + ++RedrawingDisabled; + if (GETFILE_SUCCESS(getfile(buf->b_fnum, NULL, NULL, + (options & GETF_SETMARK), lnum, forceit))) + { + --RedrawingDisabled; + + // cursor is at to BOL and w_cursor.lnum is checked due to getfile() + if (!p_sol && col != 0) + { + curwin->w_cursor.col = col; + check_cursor_col(); + curwin->w_cursor.coladd = 0; + curwin->w_set_curswant = TRUE; + } + return OK; + } + --RedrawingDisabled; + return FAIL; +} + +/* + * go to the last know line number for the current buffer + */ + static void +buflist_getfpos(void) +{ + pos_T *fpos; + + fpos = buflist_findfpos(curbuf); + + curwin->w_cursor.lnum = fpos->lnum; + check_cursor_lnum(); + + if (p_sol) + curwin->w_cursor.col = 0; + else + { + curwin->w_cursor.col = fpos->col; + check_cursor_col(); + curwin->w_cursor.coladd = 0; + curwin->w_set_curswant = TRUE; + } +} + +#if defined(FEAT_QUICKFIX) || defined(FEAT_EVAL) || defined(FEAT_SPELL) || defined(PROTO) +/* + * Find file in buffer list by name (it has to be for the current window). + * Returns NULL if not found. + */ + buf_T * +buflist_findname_exp(char_u *fname) +{ + char_u *ffname; + buf_T *buf = NULL; + + // First make the name into a full path name + ffname = FullName_save(fname, +#ifdef UNIX + TRUE // force expansion, get rid of symbolic links +#else + FALSE +#endif + ); + if (ffname != NULL) + { + buf = buflist_findname(ffname); + vim_free(ffname); + } + return buf; +} +#endif + +/* + * Find file in buffer list by name (it has to be for the current window). + * "ffname" must have a full path. + * Skips dummy buffers. + * Returns NULL if not found. + */ + buf_T * +buflist_findname(char_u *ffname) +{ +#ifdef UNIX + stat_T st; + + if (mch_stat((char *)ffname, &st) < 0) + st.st_dev = (dev_T)-1; + return buflist_findname_stat(ffname, &st); +} + +/* + * Same as buflist_findname(), but pass the stat structure to avoid getting it + * twice for the same file. + * Returns NULL if not found. + */ + static buf_T * +buflist_findname_stat( + char_u *ffname, + stat_T *stp) +{ +#endif + buf_T *buf; + + // Start at the last buffer, expect to find a match sooner. + FOR_ALL_BUFS_FROM_LAST(buf) + if ((buf->b_flags & BF_DUMMY) == 0 && !otherfile_buf(buf, ffname +#ifdef UNIX + , stp +#endif + )) + return buf; + return NULL; +} + +/* + * Find file in buffer list by a regexp pattern. + * Return fnum of the found buffer. + * Return < 0 for error. + */ + int +buflist_findpat( + char_u *pattern, + char_u *pattern_end, // pointer to first char after pattern + int unlisted, // find unlisted buffers + int diffmode UNUSED, // find diff-mode buffers only + int curtab_only) // find buffers in current tab only +{ + buf_T *buf; + int match = -1; + int find_listed; + char_u *pat; + char_u *patend; + int attempt; + char_u *p; + int toggledollar; + + // "%" is current file, "%%" or "#" is alternate file + if ((pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#')) + || (in_vim9script() && pattern_end == pattern + 2 + && pattern[0] == '%' && pattern[1] == '%')) + { + if (*pattern == '#' || pattern_end == pattern + 2) + match = curwin->w_alt_fnum; + else + match = curbuf->b_fnum; +#ifdef FEAT_DIFF + if (diffmode && !diff_mode_buf(buflist_findnr(match))) + match = -1; +#endif + } + + /* + * Try four ways of matching a listed buffer: + * attempt == 0: without '^' or '$' (at any position) + * attempt == 1: with '^' at start (only at position 0) + * attempt == 2: with '$' at end (only match at end) + * attempt == 3: with '^' at start and '$' at end (only full match) + * Repeat this for finding an unlisted buffer if there was no matching + * listed buffer. + */ + else + { + pat = file_pat_to_reg_pat(pattern, pattern_end, NULL, FALSE); + if (pat == NULL) + return -1; + patend = pat + STRLEN(pat) - 1; + toggledollar = (patend > pat && *patend == '$'); + + // First try finding a listed buffer. If not found and "unlisted" + // is TRUE, try finding an unlisted buffer. + find_listed = TRUE; + for (;;) + { + for (attempt = 0; attempt <= 3; ++attempt) + { + regmatch_T regmatch; + + // may add '^' and '$' + if (toggledollar) + *patend = (attempt < 2) ? NUL : '$'; // add/remove '$' + p = pat; + if (*p == '^' && !(attempt & 1)) // add/remove '^' + ++p; + regmatch.regprog = vim_regcomp(p, magic_isset() ? RE_MAGIC : 0); + + FOR_ALL_BUFS_FROM_LAST(buf) + { + if (regmatch.regprog == NULL) + { + // invalid pattern, possibly after switching engine + vim_free(pat); + return -1; + } + if (buf->b_p_bl == find_listed +#ifdef FEAT_DIFF + && (!diffmode || diff_mode_buf(buf)) +#endif + && buflist_match(®match, buf, FALSE) != NULL) + { + if (curtab_only) + { + // Ignore the match if the buffer is not open in + // the current tab. + win_T *wp; + + FOR_ALL_WINDOWS(wp) + if (wp->w_buffer == buf) + break; + if (wp == NULL) + continue; + } + if (match >= 0) // already found a match + { + match = -2; + break; + } + match = buf->b_fnum; // remember first match + } + } + + vim_regfree(regmatch.regprog); + if (match >= 0) // found one match + break; + } + + // Only search for unlisted buffers if there was no match with + // a listed buffer. + if (!unlisted || !find_listed || match != -1) + break; + find_listed = FALSE; + } + + vim_free(pat); + } + + if (match == -2) + semsg(_(e_more_than_one_match_for_str), pattern); + else if (match < 0) + semsg(_(e_no_matching_buffer_for_str), pattern); + return match; +} + +#ifdef FEAT_VIMINFO +typedef struct { + buf_T *buf; + char_u *match; +} bufmatch_T; +#endif + +/* + * Find all buffer names that match. + * For command line expansion of ":buf" and ":sbuf". + * Return OK if matches found, FAIL otherwise. + */ + int +ExpandBufnames( + char_u *pat, + int *num_file, + char_u ***file, + int options) +{ + int count = 0; + buf_T *buf; + int round; + char_u *p; + int attempt; + char_u *patc = NULL; +#ifdef FEAT_VIMINFO + bufmatch_T *matches = NULL; +#endif + int fuzzy; + fuzmatch_str_T *fuzmatch = NULL; + + *num_file = 0; // return values in case of FAIL + *file = NULL; + +#ifdef FEAT_DIFF + if ((options & BUF_DIFF_FILTER) && !curwin->w_p_diff) + return FAIL; +#endif + + fuzzy = cmdline_fuzzy_complete(pat); + + // Make a copy of "pat" and change "^" to "\(^\|[\/]\)" (if doing regular + // expression matching) + if (!fuzzy) + { + if (*pat == '^') + { + patc = alloc(STRLEN(pat) + 11); + if (patc == NULL) + return FAIL; + STRCPY(patc, "\\(^\\|[\\/]\\)"); + STRCPY(patc + 11, pat + 1); + } + else + patc = pat; + } + + // attempt == 0: try match with '\<', match at start of word + // attempt == 1: try match without '\<', match anywhere + for (attempt = 0; attempt <= (fuzzy ? 0 : 1); ++attempt) + { + regmatch_T regmatch; + int score = 0; + + if (!fuzzy) + { + if (attempt > 0 && patc == pat) + break; // there was no anchor, no need to try again + regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC); + } + + // round == 1: Count the matches. + // round == 2: Build the array to keep the matches. + for (round = 1; round <= 2; ++round) + { + count = 0; + FOR_ALL_BUFFERS(buf) + { + if (!buf->b_p_bl) // skip unlisted buffers + continue; +#ifdef FEAT_DIFF + if (options & BUF_DIFF_FILTER) + // Skip buffers not suitable for + // :diffget or :diffput completion. + if (buf == curbuf || !diff_mode_buf(buf)) + continue; +#endif + + if (!fuzzy) + { + if (regmatch.regprog == NULL) + { + // invalid pattern, possibly after recompiling + if (patc != pat) + vim_free(patc); + return FAIL; + } + p = buflist_match(®match, buf, p_wic); + } + else + { + p = NULL; + // first try matching with the short file name + if ((score = fuzzy_match_str(buf->b_sfname, pat)) != 0) + p = buf->b_sfname; + if (p == NULL) + { + // next try matching with the full path file name + if ((score = fuzzy_match_str(buf->b_ffname, pat)) != 0) + p = buf->b_ffname; + } + } + + if (p == NULL) + continue; + + if (round == 1) + { + ++count; + continue; + } + + if (options & WILD_HOME_REPLACE) + p = home_replace_save(buf, p); + else + p = vim_strsave(p); + + if (!fuzzy) + { +#ifdef FEAT_VIMINFO + if (matches != NULL) + { + matches[count].buf = buf; + matches[count].match = p; + count++; + } + else +#endif + (*file)[count++] = p; + } + else + { + fuzmatch[count].idx = count; + fuzmatch[count].str = p; + fuzmatch[count].score = score; + count++; + } + } + if (count == 0) // no match found, break here + break; + if (round == 1) + { + if (!fuzzy) + { + *file = ALLOC_MULT(char_u *, count); + if (*file == NULL) + { + vim_regfree(regmatch.regprog); + if (patc != pat) + vim_free(patc); + return FAIL; + } +#ifdef FEAT_VIMINFO + if (options & WILD_BUFLASTUSED) + matches = ALLOC_MULT(bufmatch_T, count); +#endif + } + else + { + fuzmatch = ALLOC_MULT(fuzmatch_str_T, count); + if (fuzmatch == NULL) + { + *num_file = 0; + *file = NULL; + return FAIL; + } + } + } + } + + if (!fuzzy) + { + vim_regfree(regmatch.regprog); + if (count) // match(es) found, break here + break; + } + } + + if (!fuzzy && patc != pat) + vim_free(patc); + +#ifdef FEAT_VIMINFO + if (!fuzzy) + { + if (matches != NULL) + { + int i; + if (count > 1) + qsort(matches, count, sizeof(bufmatch_T), buf_compare); + // if the current buffer is first in the list, place it at the end + if (matches[0].buf == curbuf) + { + for (i = 1; i < count; i++) + (*file)[i-1] = matches[i].match; + (*file)[count-1] = matches[0].match; + } + else + { + for (i = 0; i < count; i++) + (*file)[i] = matches[i].match; + } + vim_free(matches); + } + } + else + { + if (fuzzymatches_to_strmatches(fuzmatch, file, count, FALSE) == FAIL) + return FAIL; + } +#endif + + *num_file = count; + return (count == 0 ? FAIL : OK); +} + +/* + * Check for a match on the file name for buffer "buf" with regprog "prog". + * Note that rmp->regprog may become NULL when switching regexp engine. + */ + static char_u * +buflist_match( + regmatch_T *rmp, + buf_T *buf, + int ignore_case) // when TRUE ignore case, when FALSE use 'fic' +{ + char_u *match; + + // First try the short file name, then the long file name. + match = fname_match(rmp, buf->b_sfname, ignore_case); + if (match == NULL && rmp->regprog != NULL) + match = fname_match(rmp, buf->b_ffname, ignore_case); + + return match; +} + +/* + * Try matching the regexp in "rmp->regprog" with file name "name". + * Note that rmp->regprog may become NULL when switching regexp engine. + * Return "name" when there is a match, NULL when not. + */ + static char_u * +fname_match( + regmatch_T *rmp, + char_u *name, + int ignore_case) // when TRUE ignore case, when FALSE use 'fic' +{ + char_u *match = NULL; + char_u *p; + + // extra check for valid arguments + if (name == NULL || rmp->regprog == NULL) + return NULL; + + // Ignore case when 'fileignorecase' or the argument is set. + rmp->rm_ic = p_fic || ignore_case; + if (vim_regexec(rmp, name, (colnr_T)0)) + match = name; + else if (rmp->regprog != NULL) + { + // Replace $(HOME) with '~' and try matching again. + p = home_replace_save(NULL, name); + if (p != NULL && vim_regexec(rmp, p, (colnr_T)0)) + match = name; + vim_free(p); + } + + return match; +} + +/* + * Find a file in the buffer list by buffer number. + */ + buf_T * +buflist_findnr(int nr) +{ + char_u key[VIM_SIZEOF_INT * 2 + 1]; + hashitem_T *hi; + + if (nr == 0) + nr = curwin->w_alt_fnum; + sprintf((char *)key, "%x", nr); + hi = hash_find(&buf_hashtab, key); + + if (!HASHITEM_EMPTY(hi)) + return (buf_T *)(hi->hi_key + - ((unsigned)(curbuf->b_key - (char_u *)curbuf))); + return NULL; +} + +/* + * Get name of file 'n' in the buffer list. + * When the file has no name an empty string is returned. + * home_replace() is used to shorten the file name (used for marks). + * Returns a pointer to allocated memory, of NULL when failed. + */ + char_u * +buflist_nr2name( + int n, + int fullname, + int helptail) // for help buffers return tail only +{ + buf_T *buf; + + buf = buflist_findnr(n); + if (buf == NULL) + return NULL; + return home_replace_save(helptail ? buf : NULL, + fullname ? buf->b_ffname : buf->b_fname); +} + +/* + * Set the "lnum" and "col" for the buffer "buf" and the current window. + * When "copy_options" is TRUE save the local window option values. + * When "lnum" is 0 only do the options. + */ + void +buflist_setfpos( + buf_T *buf, + win_T *win, // may be NULL when using :badd + linenr_T lnum, + colnr_T col, + int copy_options) +{ + wininfo_T *wip; + + FOR_ALL_BUF_WININFO(buf, wip) + if (wip->wi_win == win) + break; + if (wip == NULL) + { + // allocate a new entry + wip = ALLOC_CLEAR_ONE(wininfo_T); + if (wip == NULL) + return; + wip->wi_win = win; + if (lnum == 0) // set lnum even when it's 0 + lnum = 1; + } + else + { + // remove the entry from the list + if (wip->wi_prev) + wip->wi_prev->wi_next = wip->wi_next; + else + buf->b_wininfo = wip->wi_next; + if (wip->wi_next) + wip->wi_next->wi_prev = wip->wi_prev; + if (copy_options && wip->wi_optset) + { + clear_winopt(&wip->wi_opt); +#ifdef FEAT_FOLDING + deleteFoldRecurse(&wip->wi_folds); +#endif + } + } + if (lnum != 0) + { + wip->wi_fpos.lnum = lnum; + wip->wi_fpos.col = col; + } + if (win != NULL) + wip->wi_changelistidx = win->w_changelistidx; + if (copy_options && win != NULL) + { + // Save the window-specific option values. + copy_winopt(&win->w_onebuf_opt, &wip->wi_opt); +#ifdef FEAT_FOLDING + wip->wi_fold_manual = win->w_fold_manual; + cloneFoldGrowArray(&win->w_folds, &wip->wi_folds); +#endif + wip->wi_optset = TRUE; + } + + // insert the entry in front of the list + wip->wi_next = buf->b_wininfo; + buf->b_wininfo = wip; + wip->wi_prev = NULL; + if (wip->wi_next) + wip->wi_next->wi_prev = wip; +} + +#ifdef FEAT_DIFF +/* + * Return TRUE when "wip" has 'diff' set and the diff is only for another tab + * page. That's because a diff is local to a tab page. + */ + static int +wininfo_other_tab_diff(wininfo_T *wip) +{ + win_T *wp; + + if (!wip->wi_opt.wo_diff) + return FALSE; + + FOR_ALL_WINDOWS(wp) + // return FALSE when it's a window in the current tab page, thus + // the buffer was in diff mode here + if (wip->wi_win == wp) + return FALSE; + return TRUE; +} +#endif + +/* + * Find info for the current window in buffer "buf". + * If not found, return the info for the most recently used window. + * When "need_options" is TRUE skip entries where wi_optset is FALSE. + * When "skip_diff_buffer" is TRUE avoid windows with 'diff' set that is in + * another tab page. + * Returns NULL when there isn't any info. + */ + static wininfo_T * +find_wininfo( + buf_T *buf, + int need_options, + int skip_diff_buffer UNUSED) +{ + wininfo_T *wip; + + FOR_ALL_BUF_WININFO(buf, wip) + if (wip->wi_win == curwin +#ifdef FEAT_DIFF + && (!skip_diff_buffer || !wininfo_other_tab_diff(wip)) +#endif + + && (!need_options || wip->wi_optset)) + break; + + if (wip != NULL) + return wip; + + // If no wininfo for curwin, use the first in the list (that doesn't have + // 'diff' set and is in another tab page). + // If "need_options" is TRUE skip entries that don't have options set, + // unless the window is editing "buf", so we can copy from the window + // itself. +#ifdef FEAT_DIFF + if (skip_diff_buffer) + { + FOR_ALL_BUF_WININFO(buf, wip) + if (!wininfo_other_tab_diff(wip) + && (!need_options || wip->wi_optset + || (wip->wi_win != NULL + && wip->wi_win->w_buffer == buf))) + break; + } + else +#endif + wip = buf->b_wininfo; + return wip; +} + +/* + * Reset the local window options to the values last used in this window. + * If the buffer wasn't used in this window before, use the values from + * the most recently used window. If the values were never set, use the + * global values for the window. + */ + void +get_winopts(buf_T *buf) +{ + wininfo_T *wip; + + clear_winopt(&curwin->w_onebuf_opt); +#ifdef FEAT_FOLDING + clearFolding(curwin); +#endif + + wip = find_wininfo(buf, TRUE, TRUE); + if (wip != NULL && wip->wi_win != NULL + && wip->wi_win != curwin && wip->wi_win->w_buffer == buf) + { + // The buffer is currently displayed in the window: use the actual + // option values instead of the saved (possibly outdated) values. + win_T *wp = wip->wi_win; + + copy_winopt(&wp->w_onebuf_opt, &curwin->w_onebuf_opt); +#ifdef FEAT_FOLDING + curwin->w_fold_manual = wp->w_fold_manual; + curwin->w_foldinvalid = TRUE; + cloneFoldGrowArray(&wp->w_folds, &curwin->w_folds); +#endif + } + else if (wip != NULL && wip->wi_optset) + { + // the buffer was displayed in the current window earlier + copy_winopt(&wip->wi_opt, &curwin->w_onebuf_opt); +#ifdef FEAT_FOLDING + curwin->w_fold_manual = wip->wi_fold_manual; + curwin->w_foldinvalid = TRUE; + cloneFoldGrowArray(&wip->wi_folds, &curwin->w_folds); +#endif + } + else + copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt); + if (wip != NULL) + curwin->w_changelistidx = wip->wi_changelistidx; + +#ifdef FEAT_FOLDING + // Set 'foldlevel' to 'foldlevelstart' if it's not negative. + if (p_fdls >= 0) + curwin->w_p_fdl = p_fdls; +#endif + after_copy_winopt(curwin); +} + +/* + * Find the position (lnum and col) for the buffer 'buf' for the current + * window. + * Returns a pointer to no_position if no position is found. + */ + pos_T * +buflist_findfpos(buf_T *buf) +{ + wininfo_T *wip; + static pos_T no_position = {1, 0, 0}; + + wip = find_wininfo(buf, FALSE, FALSE); + if (wip != NULL) + return &(wip->wi_fpos); + else + return &no_position; +} + +/* + * Find the lnum for the buffer 'buf' for the current window. + */ + linenr_T +buflist_findlnum(buf_T *buf) +{ + return buflist_findfpos(buf)->lnum; +} + +/* + * List all known file names (for :files and :buffers command). + */ + void +buflist_list(exarg_T *eap) +{ + buf_T *buf = firstbuf; + int len; + int i; + int ro_char; + int changed_char; +#ifdef FEAT_TERMINAL + int job_running; + int job_none_open; +#endif + +#ifdef FEAT_VIMINFO + garray_T buflist; + buf_T **buflist_data = NULL, **p; + + if (vim_strchr(eap->arg, 't')) + { + ga_init2(&buflist, sizeof(buf_T *), 50); + FOR_ALL_BUFFERS(buf) + { + if (ga_grow(&buflist, 1) == OK) + ((buf_T **)buflist.ga_data)[buflist.ga_len++] = buf; + } + + qsort(buflist.ga_data, (size_t)buflist.ga_len, + sizeof(buf_T *), buf_compare); + + buflist_data = (buf_T **)buflist.ga_data; + buf = *buflist_data; + } + p = buflist_data; + + for (; buf != NULL && !got_int; buf = buflist_data != NULL + ? (++p < buflist_data + buflist.ga_len ? *p : NULL) + : buf->b_next) +#else + for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next) +#endif + { +#ifdef FEAT_TERMINAL + job_running = term_job_running(buf->b_term); + job_none_open = term_none_open(buf->b_term); +#endif + // skip unlisted buffers, unless ! was used + if ((!buf->b_p_bl && !eap->forceit && !vim_strchr(eap->arg, 'u')) + || (vim_strchr(eap->arg, 'u') && buf->b_p_bl) + || (vim_strchr(eap->arg, '+') + && ((buf->b_flags & BF_READERR) || !bufIsChanged(buf))) + || (vim_strchr(eap->arg, 'a') + && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows == 0)) + || (vim_strchr(eap->arg, 'h') + && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows != 0)) +#ifdef FEAT_TERMINAL + || (vim_strchr(eap->arg, 'R') + && (!job_running || (job_running && job_none_open))) + || (vim_strchr(eap->arg, '?') + && (!job_running || (job_running && !job_none_open))) + || (vim_strchr(eap->arg, 'F') + && (job_running || buf->b_term == NULL)) +#endif + || (vim_strchr(eap->arg, '-') && buf->b_p_ma) + || (vim_strchr(eap->arg, '=') && !buf->b_p_ro) + || (vim_strchr(eap->arg, 'x') && !(buf->b_flags & BF_READERR)) + || (vim_strchr(eap->arg, '%') && buf != curbuf) + || (vim_strchr(eap->arg, '#') + && (buf == curbuf || curwin->w_alt_fnum != buf->b_fnum))) + continue; + if (buf_spname(buf) != NULL) + vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1); + else + home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE); + if (message_filtered(NameBuff)) + continue; + + changed_char = (buf->b_flags & BF_READERR) ? 'x' + : (bufIsChanged(buf) ? '+' : ' '); +#ifdef FEAT_TERMINAL + if (job_running) + { + if (job_none_open) + ro_char = '?'; + else + ro_char = 'R'; + changed_char = ' '; // bufIsChanged() returns TRUE to avoid + // closing, but it's not actually changed. + } + else if (buf->b_term != NULL) + ro_char = 'F'; + else +#endif + ro_char = !buf->b_p_ma ? '-' : (buf->b_p_ro ? '=' : ' '); + + msg_putchar('\n'); + len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"", + buf->b_fnum, + buf->b_p_bl ? ' ' : 'u', + buf == curbuf ? '%' : + (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '), + buf->b_ml.ml_mfp == NULL ? ' ' : + (buf->b_nwindows == 0 ? 'h' : 'a'), + ro_char, + changed_char, + NameBuff); + if (len > IOSIZE - 20) + len = IOSIZE - 20; + + // put "line 999" in column 40 or after the file name + i = 40 - vim_strsize(IObuff); + do + IObuff[len++] = ' '; + while (--i > 0 && len < IOSIZE - 18); +#ifdef FEAT_VIMINFO + if (vim_strchr(eap->arg, 't') && buf->b_last_used) + add_time(IObuff + len, (size_t)(IOSIZE - len), buf->b_last_used); + else +#endif + vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), + _("line %ld"), buf == curbuf ? curwin->w_cursor.lnum + : (long)buflist_findlnum(buf)); + msg_outtrans(IObuff); + out_flush(); // output one line at a time + ui_breakcheck(); + } + +#ifdef FEAT_VIMINFO + if (buflist_data) + ga_clear(&buflist); +#endif +} + +/* + * Get file name and line number for file 'fnum'. + * Used by DoOneCmd() for translating '%' and '#'. + * Used by insert_reg() and cmdline_paste() for '#' register. + * Return FAIL if not found, OK for success. + */ + int +buflist_name_nr( + int fnum, + char_u **fname, + linenr_T *lnum) +{ + buf_T *buf; + + buf = buflist_findnr(fnum); + if (buf == NULL || buf->b_fname == NULL) + return FAIL; + + *fname = buf->b_fname; + *lnum = buflist_findlnum(buf); + + return OK; +} + +/* + * Set the file name for "buf"' to "ffname_arg", short file name to + * "sfname_arg". + * The file name with the full path is also remembered, for when :cd is used. + * Returns FAIL for failure (file name already in use by other buffer) + * OK otherwise. + */ + int +setfname( + buf_T *buf, + char_u *ffname_arg, + char_u *sfname_arg, + int message) // give message when buffer already exists +{ + char_u *ffname = ffname_arg; + char_u *sfname = sfname_arg; + buf_T *obuf = NULL; +#ifdef UNIX + stat_T st; +#endif + + if (ffname == NULL || *ffname == NUL) + { + // Removing the name. + if (buf->b_sfname != buf->b_ffname) + VIM_CLEAR(buf->b_sfname); + else + buf->b_sfname = NULL; + VIM_CLEAR(buf->b_ffname); +#ifdef UNIX + st.st_dev = (dev_T)-1; +#endif + } + else + { + fname_expand(buf, &ffname, &sfname); // will allocate ffname + if (ffname == NULL) // out of memory + return FAIL; + + /* + * If the file name is already used in another buffer: + * - if the buffer is loaded, fail + * - if the buffer is not loaded, delete it from the list + */ +#ifdef UNIX + if (mch_stat((char *)ffname, &st) < 0) + st.st_dev = (dev_T)-1; +#endif + if (!(buf->b_flags & BF_DUMMY)) +#ifdef UNIX + obuf = buflist_findname_stat(ffname, &st); +#else + obuf = buflist_findname(ffname); +#endif + if (obuf != NULL && obuf != buf) + { + win_T *win; + tabpage_T *tab; + int in_use = FALSE; + + // during startup a window may use a buffer that is not loaded yet + FOR_ALL_TAB_WINDOWS(tab, win) + if (win->w_buffer == obuf) + in_use = TRUE; + + // it's loaded or used in a window, fail + if (obuf->b_ml.ml_mfp != NULL || in_use) + { + if (message) + emsg(_(e_buffer_with_this_name_already_exists)); + vim_free(ffname); + return FAIL; + } + // delete from the list + close_buffer(NULL, obuf, DOBUF_WIPE, FALSE, FALSE); + } + sfname = vim_strsave(sfname); + if (ffname == NULL || sfname == NULL) + { + vim_free(sfname); + vim_free(ffname); + return FAIL; + } +#ifdef USE_FNAME_CASE + fname_case(sfname, 0); // set correct case for short file name +#endif + if (buf->b_sfname != buf->b_ffname) + vim_free(buf->b_sfname); + vim_free(buf->b_ffname); + buf->b_ffname = ffname; + buf->b_sfname = sfname; + } + buf->b_fname = buf->b_sfname; +#ifdef UNIX + if (st.st_dev == (dev_T)-1) + buf->b_dev_valid = FALSE; + else + { + buf->b_dev_valid = TRUE; + buf->b_dev = st.st_dev; + buf->b_ino = st.st_ino; + } +#endif + + buf->b_shortname = FALSE; + + buf_name_changed(buf); + return OK; +} + +/* + * Crude way of changing the name of a buffer. Use with care! + * The name should be relative to the current directory. + */ + void +buf_set_name(int fnum, char_u *name) +{ + buf_T *buf; + + buf = buflist_findnr(fnum); + if (buf == NULL) + return; + + if (buf->b_sfname != buf->b_ffname) + vim_free(buf->b_sfname); + vim_free(buf->b_ffname); + buf->b_ffname = vim_strsave(name); + buf->b_sfname = NULL; + // Allocate ffname and expand into full path. Also resolves .lnk + // files on Win32. + fname_expand(buf, &buf->b_ffname, &buf->b_sfname); + buf->b_fname = buf->b_sfname; +} + +/* + * Take care of what needs to be done when the name of buffer "buf" has + * changed. + */ + void +buf_name_changed(buf_T *buf) +{ + /* + * If the file name changed, also change the name of the swapfile + */ + if (buf->b_ml.ml_mfp != NULL) + ml_setname(buf); + +#ifdef FEAT_TERMINAL + if (buf->b_term != NULL) + term_clear_status_text(buf->b_term); +#endif + + if (curwin->w_buffer == buf) + check_arg_idx(curwin); // check file name for arg list + maketitle(); // set window title + status_redraw_all(); // status lines need to be redrawn + fmarks_check_names(buf); // check named file marks + ml_timestamp(buf); // reset timestamp +} + +/* + * set alternate file name for current window + * + * Used by do_one_cmd(), do_write() and do_ecmd(). + * Return the buffer. + */ + buf_T * +setaltfname( + char_u *ffname, + char_u *sfname, + linenr_T lnum) +{ + buf_T *buf; + + // Create a buffer. 'buflisted' is not set if it's a new buffer + buf = buflist_new(ffname, sfname, lnum, 0); + if (buf != NULL && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0) + curwin->w_alt_fnum = buf->b_fnum; + return buf; +} + +/* + * Get alternate file name for current window. + * Return NULL if there isn't any, and give error message if requested. + */ + char_u * +getaltfname( + int errmsg) // give error message +{ + char_u *fname; + linenr_T dummy; + + if (buflist_name_nr(0, &fname, &dummy) == FAIL) + { + if (errmsg) + emsg(_(e_no_alternate_file)); + return NULL; + } + return fname; +} + +/* + * Add a file name to the buflist and return its number. + * Uses same flags as buflist_new(), except BLN_DUMMY. + * + * used by qf_init(), main() and doarglist() + */ + int +buflist_add(char_u *fname, int flags) +{ + buf_T *buf; + + buf = buflist_new(fname, NULL, (linenr_T)0, flags); + if (buf != NULL) + return buf->b_fnum; + return 0; +} + +#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) +/* + * Adjust slashes in file names. Called after 'shellslash' was set. + */ + void +buflist_slash_adjust(void) +{ + buf_T *bp; + + FOR_ALL_BUFFERS(bp) + { + if (bp->b_ffname != NULL) + slash_adjust(bp->b_ffname); + if (bp->b_sfname != NULL) + slash_adjust(bp->b_sfname); + } +} +#endif + +/* + * Set alternate cursor position for the current buffer and window "win". + * Also save the local window option values. + */ + void +buflist_altfpos(win_T *win) +{ + buflist_setfpos(curbuf, win, win->w_cursor.lnum, win->w_cursor.col, TRUE); +} + +/* + * Return TRUE if 'ffname' is not the same file as current file. + * Fname must have a full path (expanded by mch_FullName()). + */ + int +otherfile(char_u *ffname) +{ + return otherfile_buf(curbuf, ffname +#ifdef UNIX + , NULL +#endif + ); +} + + static int +otherfile_buf( + buf_T *buf, + char_u *ffname +#ifdef UNIX + , stat_T *stp +#endif + ) +{ + // no name is different + if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL) + return TRUE; + if (fnamecmp(ffname, buf->b_ffname) == 0) + return FALSE; +#ifdef UNIX + { + stat_T st; + + // If no stat_T given, get it now + if (stp == NULL) + { + if (!buf->b_dev_valid || mch_stat((char *)ffname, &st) < 0) + st.st_dev = (dev_T)-1; + stp = &st; + } + // Use dev/ino to check if the files are the same, even when the names + // are different (possible with links). Still need to compare the + // name above, for when the file doesn't exist yet. + // Problem: The dev/ino changes when a file is deleted (and created + // again) and remains the same when renamed/moved. We don't want to + // mch_stat() each buffer each time, that would be too slow. Get the + // dev/ino again when they appear to match, but not when they appear + // to be different: Could skip a buffer when it's actually the same + // file. + if (buf_same_ino(buf, stp)) + { + buf_setino(buf); + if (buf_same_ino(buf, stp)) + return FALSE; + } + } +#endif + return TRUE; +} + +#if defined(UNIX) || defined(PROTO) +/* + * Set inode and device number for a buffer. + * Must always be called when b_fname is changed!. + */ + void +buf_setino(buf_T *buf) +{ + stat_T st; + + if (buf->b_fname != NULL && mch_stat((char *)buf->b_fname, &st) >= 0) + { + buf->b_dev_valid = TRUE; + buf->b_dev = st.st_dev; + buf->b_ino = st.st_ino; + } + else + buf->b_dev_valid = FALSE; +} + +/* + * Return TRUE if dev/ino in buffer "buf" matches with "stp". + */ + static int +buf_same_ino( + buf_T *buf, + stat_T *stp) +{ + return (buf->b_dev_valid + && stp->st_dev == buf->b_dev + && stp->st_ino == buf->b_ino); +} +#endif + +/* + * Print info about the current buffer. + */ + void +fileinfo( + int fullname, // when non-zero print full path + int shorthelp, + int dont_truncate) +{ + char_u *name; + int n; + char *p; + char *buffer; + size_t len; + + buffer = alloc(IOSIZE); + if (buffer == NULL) + return; + + if (fullname > 1) // 2 CTRL-G: include buffer number + { + vim_snprintf(buffer, IOSIZE, "buf %d: ", curbuf->b_fnum); + p = buffer + STRLEN(buffer); + } + else + p = buffer; + + *p++ = '"'; + if (buf_spname(curbuf) != NULL) + vim_strncpy((char_u *)p, buf_spname(curbuf), IOSIZE - (p - buffer) - 1); + else + { + if (!fullname && curbuf->b_fname != NULL) + name = curbuf->b_fname; + else + name = curbuf->b_ffname; + home_replace(shorthelp ? curbuf : NULL, name, (char_u *)p, + (int)(IOSIZE - (p - buffer)), TRUE); + } + + vim_snprintf_add(buffer, IOSIZE, "\"%s%s%s%s%s%s", + curbufIsChanged() ? (shortmess(SHM_MOD) + ? " [+]" : _(" [Modified]")) : " ", + (curbuf->b_flags & BF_NOTEDITED) && !bt_dontwrite(curbuf) + ? _("[Not edited]") : "", + (curbuf->b_flags & BF_NEW) && !bt_dontwrite(curbuf) + ? new_file_message() : "", + (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "", + curbuf->b_p_ro ? (shortmess(SHM_RO) ? _("[RO]") + : _("[readonly]")) : "", + (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK) + || curbuf->b_p_ro) ? + " " : ""); + // With 32 bit longs and more than 21,474,836 lines multiplying by 100 + // causes an overflow, thus for large numbers divide instead. + if (curwin->w_cursor.lnum > 1000000L) + n = (int)(((long)curwin->w_cursor.lnum) / + ((long)curbuf->b_ml.ml_line_count / 100L)); + else + n = (int)(((long)curwin->w_cursor.lnum * 100L) / + (long)curbuf->b_ml.ml_line_count); + if (curbuf->b_ml.ml_flags & ML_EMPTY) + vim_snprintf_add(buffer, IOSIZE, "%s", _(no_lines_msg)); + else if (p_ru) + // Current line and column are already on the screen -- webb + vim_snprintf_add(buffer, IOSIZE, + NGETTEXT("%ld line --%d%%--", "%ld lines --%d%%--", + curbuf->b_ml.ml_line_count), + (long)curbuf->b_ml.ml_line_count, n); + else + { + vim_snprintf_add(buffer, IOSIZE, + _("line %ld of %ld --%d%%-- col "), + (long)curwin->w_cursor.lnum, + (long)curbuf->b_ml.ml_line_count, + n); + validate_virtcol(); + len = STRLEN(buffer); + col_print((char_u *)buffer + len, IOSIZE - len, + (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); + } + + (void)append_arg_number(curwin, (char_u *)buffer, IOSIZE, + !shortmess(SHM_FILE)); + + if (dont_truncate) + { + // Temporarily set msg_scroll to avoid the message being truncated. + // First call msg_start() to get the message in the right place. + msg_start(); + n = msg_scroll; + msg_scroll = TRUE; + msg(buffer); + msg_scroll = n; + } + else + { + p = msg_trunc_attr(buffer, FALSE, 0); + if (restart_edit != 0 || (msg_scrolled && !need_wait_return)) + // Need to repeat the message after redrawing when: + // - When restart_edit is set (otherwise there will be a delay + // before redrawing). + // - When the screen was scrolled but there is no wait-return + // prompt. + set_keep_msg((char_u *)p, 0); + } + + vim_free(buffer); +} + + void +col_print( + char_u *buf, + size_t buflen, + int col, + int vcol) +{ + if (col == vcol) + vim_snprintf((char *)buf, buflen, "%d", col); + else + vim_snprintf((char *)buf, buflen, "%d-%d", col, vcol); +} + +static char_u *lasttitle = NULL; +static char_u *lasticon = NULL; + +/* + * Put the file name in the title bar and icon of the window. + */ + void +maketitle(void) +{ + char_u *p; + char_u *title_str = NULL; + char_u *icon_str = NULL; + int maxlen = 0; + int len; + int mustset; + char_u buf[IOSIZE]; + int off; + + if (!redrawing()) + { + // Postpone updating the title when 'lazyredraw' is set. + need_maketitle = TRUE; + return; + } + + need_maketitle = FALSE; + if (!p_title && !p_icon && lasttitle == NULL && lasticon == NULL) + return; // nothing to do + + if (p_title) + { + if (p_titlelen > 0) + { + maxlen = p_titlelen * Columns / 100; + if (maxlen < 10) + maxlen = 10; + } + + title_str = buf; + if (*p_titlestring != NUL) + { +#ifdef FEAT_STL_OPT + if (stl_syntax & STL_IN_TITLE) + build_stl_str_hl(curwin, title_str, sizeof(buf), p_titlestring, + (char_u *)"titlestring", 0, + 0, maxlen, NULL, NULL); + else +#endif + title_str = p_titlestring; + } + else + { + // format: "fname + (path) (1 of 2) - VIM" + +#define SPACE_FOR_FNAME (IOSIZE - 100) +#define SPACE_FOR_DIR (IOSIZE - 20) +#define SPACE_FOR_ARGNR (IOSIZE - 10) // at least room for " - VIM" + if (curbuf->b_fname == NULL) + vim_strncpy(buf, (char_u *)_("[No Name]"), SPACE_FOR_FNAME); +#ifdef FEAT_TERMINAL + else if (curbuf->b_term != NULL) + { + vim_strncpy(buf, term_get_status_text(curbuf->b_term), + SPACE_FOR_FNAME); + } +#endif + else + { + p = transstr(gettail(curbuf->b_fname)); + vim_strncpy(buf, p, SPACE_FOR_FNAME); + vim_free(p); + } + +#ifdef FEAT_TERMINAL + if (curbuf->b_term == NULL) +#endif + switch (bufIsChanged(curbuf) + + (curbuf->b_p_ro * 2) + + (!curbuf->b_p_ma * 4)) + { + case 1: STRCAT(buf, " +"); break; + case 2: STRCAT(buf, " ="); break; + case 3: STRCAT(buf, " =+"); break; + case 4: + case 6: STRCAT(buf, " -"); break; + case 5: + case 7: STRCAT(buf, " -+"); break; + } + + if (curbuf->b_fname != NULL +#ifdef FEAT_TERMINAL + && curbuf->b_term == NULL +#endif + ) + { + // Get path of file, replace home dir with ~ + off = (int)STRLEN(buf); + buf[off++] = ' '; + buf[off++] = '('; + home_replace(curbuf, curbuf->b_ffname, + buf + off, SPACE_FOR_DIR - off, TRUE); +#ifdef BACKSLASH_IN_FILENAME + // avoid "c:/name" to be reduced to "c" + if (isalpha(buf[off]) && buf[off + 1] == ':') + off += 2; +#endif + // remove the file name + p = gettail_sep(buf + off); + if (p == buf + off) + { + // must be a help buffer + vim_strncpy(buf + off, (char_u *)_("help"), + (size_t)(SPACE_FOR_DIR - off - 1)); + } + else + *p = NUL; + + // Translate unprintable chars and concatenate. Keep some + // room for the server name. When there is no room (very long + // file name) use (...). + if (off < SPACE_FOR_DIR) + { + p = transstr(buf + off); + vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - off)); + vim_free(p); + } + else + { + vim_strncpy(buf + off, (char_u *)"...", + (size_t)(SPACE_FOR_ARGNR - off)); + } + STRCAT(buf, ")"); + } + + append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE); + +#if defined(FEAT_CLIENTSERVER) + if (serverName != NULL) + { + STRCAT(buf, " - "); + vim_strcat(buf, serverName, IOSIZE); + } + else +#endif + STRCAT(buf, " - VIM"); + + if (maxlen > 0) + { + // make it shorter by removing a bit in the middle + if (vim_strsize(buf) > maxlen) + trunc_string(buf, buf, maxlen, IOSIZE); + } + } + } + mustset = value_changed(title_str, &lasttitle); + + if (p_icon) + { + icon_str = buf; + if (*p_iconstring != NUL) + { +#ifdef FEAT_STL_OPT + if (stl_syntax & STL_IN_ICON) + build_stl_str_hl(curwin, icon_str, sizeof(buf), p_iconstring, + (char_u *)"iconstring", 0, 0, 0, NULL, NULL); + else +#endif + icon_str = p_iconstring; + } + else + { + if (buf_spname(curbuf) != NULL) + p = buf_spname(curbuf); + else // use file name only in icon + p = gettail(curbuf->b_ffname); + *icon_str = NUL; + // Truncate name at 100 bytes. + len = (int)STRLEN(p); + if (len > 100) + { + len -= 100; + if (has_mbyte) + len += (*mb_tail_off)(p, p + len) + 1; + p += len; + } + STRCPY(icon_str, p); + trans_characters(icon_str, IOSIZE); + } + } + + mustset |= value_changed(icon_str, &lasticon); + + if (mustset) + resettitle(); +} + +/* + * Used for title and icon: Check if "str" differs from "*last". Set "*last" + * from "str" if it does. + * Return TRUE if resettitle() is to be called. + */ + static int +value_changed(char_u *str, char_u **last) +{ + if ((str == NULL) != (*last == NULL) + || (str != NULL && *last != NULL && STRCMP(str, *last) != 0)) + { + vim_free(*last); + if (str == NULL) + { + *last = NULL; + mch_restore_title( + last == &lasttitle ? SAVE_RESTORE_TITLE : SAVE_RESTORE_ICON); + } + else + { + *last = vim_strsave(str); + return TRUE; + } + } + return FALSE; +} + +/* + * Put current window title back (used after calling a shell) + */ + void +resettitle(void) +{ + mch_settitle(lasttitle, lasticon); +} + +# if defined(EXITFREE) || defined(PROTO) + void +free_titles(void) +{ + vim_free(lasttitle); + vim_free(lasticon); +} +# endif + + +#if defined(FEAT_STL_OPT) || defined(FEAT_GUI_TABLINE) || defined(PROTO) + +/* + * Used for building in the status line. + */ +typedef struct +{ + char_u *stl_start; + int stl_minwid; + int stl_maxwid; + enum { + Normal, + Empty, + Group, + Separate, + Highlight, + TabPage, + Trunc + } stl_type; +} stl_item_T; + +static size_t stl_items_len = 20; // Initial value, grows as needed. +static stl_item_T *stl_items = NULL; +static int *stl_groupitem = NULL; +static stl_hlrec_T *stl_hltab = NULL; +static stl_hlrec_T *stl_tabtab = NULL; +static int *stl_separator_locations = NULL; + +/* + * Build a string from the status line items in "fmt". + * Return length of string in screen cells. + * + * Normally works for window "wp", except when working for 'tabline' then it + * is "curwin". + * + * Items are drawn interspersed with the text that surrounds it + * Specials: %-(xxx%) => group, %= => separation marker, %< => truncation + * Item: %-. All but are optional + * + * If maxwidth is not zero, the string will be filled at any middle marker + * or truncated if too long, fillchar is used for all whitespace. + */ + int +build_stl_str_hl( + win_T *wp, + char_u *out, // buffer to write into != NameBuff + size_t outlen, // length of out[] + char_u *fmt, + char_u *opt_name, // option name corresponding to "fmt" + int opt_scope, // scope for "opt_name" + int fillchar, + int maxwidth, + stl_hlrec_T **hltab, // return: HL attributes (can be NULL) + stl_hlrec_T **tabtab) // return: tab page nrs (can be NULL) +{ + linenr_T lnum; + size_t len; + char_u *p; + char_u *s; + char_u *t; + int byteval; +#ifdef FEAT_EVAL + int use_sandbox; + win_T *save_curwin; + buf_T *save_curbuf; + int save_VIsual_active; +#endif + int empty_line; + colnr_T virtcol; + long l; + long n; + int prevchar_isflag; + int prevchar_isitem; + int itemisflag; + int fillable; + char_u *str; + long num; + int width; + int itemcnt; + int curitem; + int group_end_userhl; + int group_start_userhl; + int groupdepth; +#ifdef FEAT_EVAL + int evaldepth; +#endif + int minwid; + int maxwid; + int zeropad; + char_u base; + char_u opt; +#define TMPLEN 70 + char_u buf_tmp[TMPLEN]; + char_u win_tmp[TMPLEN]; + char_u *usefmt = fmt; + stl_hlrec_T *sp; + int save_redraw_not_allowed = redraw_not_allowed; + int save_KeyTyped = KeyTyped; + // TODO: find out why using called_emsg_before makes tests fail, does it + // matter? + // int called_emsg_before = called_emsg; + int did_emsg_before = did_emsg; + + // When inside update_screen() we do not want redrawing a statusline, + // ruler, title, etc. to trigger another redraw, it may cause an endless + // loop. + if (updating_screen) + redraw_not_allowed = TRUE; + + if (stl_items == NULL) + { + stl_items = ALLOC_MULT(stl_item_T, stl_items_len); + stl_groupitem = ALLOC_MULT(int, stl_items_len); + + // Allocate one more, because the last element is used to indicate the + // end of the list. + stl_hltab = ALLOC_MULT(stl_hlrec_T, stl_items_len + 1); + stl_tabtab = ALLOC_MULT(stl_hlrec_T, stl_items_len + 1); + + stl_separator_locations = ALLOC_MULT(int, stl_items_len); + } + +#ifdef FEAT_EVAL + // if "fmt" was set insecurely it needs to be evaluated in the sandbox + use_sandbox = was_set_insecurely(opt_name, opt_scope); + + // When the format starts with "%!" then evaluate it as an expression and + // use the result as the actual format string. + if (fmt[0] == '%' && fmt[1] == '!') + { + typval_T tv; + + tv.v_type = VAR_NUMBER; + tv.vval.v_number = wp->w_id; + set_var((char_u *)"g:statusline_winid", &tv, FALSE); + + usefmt = eval_to_string_safe(fmt + 2, use_sandbox, FALSE, FALSE); + if (usefmt == NULL) + usefmt = fmt; + + do_unlet((char_u *)"g:statusline_winid", TRUE); + } +#endif + + if (fillchar == 0) + fillchar = ' '; + + // The cursor in windows other than the current one isn't always + // up-to-date, esp. because of autocommands and timers. + lnum = wp->w_cursor.lnum; + if (lnum > wp->w_buffer->b_ml.ml_line_count) + { + lnum = wp->w_buffer->b_ml.ml_line_count; + wp->w_cursor.lnum = lnum; + } + + // Get line & check if empty (cursorpos will show "0-1"). Note that + // p will become invalid when getting another buffer line. + p = ml_get_buf(wp->w_buffer, lnum, FALSE); + empty_line = (*p == NUL); + + // Get the byte value now, in case we need it below. This is more efficient + // than making a copy of the line. + len = STRLEN(p); + if (wp->w_cursor.col > (colnr_T)len) + { + // Line may have changed since checking the cursor column, or the lnum + // was adjusted above. + wp->w_cursor.col = (colnr_T)len; + wp->w_cursor.coladd = 0; + byteval = 0; + } + else + byteval = (*mb_ptr2char)(p + wp->w_cursor.col); + + groupdepth = 0; +#ifdef FEAT_EVAL + evaldepth = 0; +#endif + p = out; + curitem = 0; + prevchar_isflag = TRUE; + prevchar_isitem = FALSE; + for (s = usefmt; *s != NUL; ) + { + if (curitem == (int)stl_items_len) + { + size_t new_len = stl_items_len * 3 / 2; + + stl_item_T *new_items = + vim_realloc(stl_items, sizeof(stl_item_T) * new_len); + if (new_items == NULL) + break; + stl_items = new_items; + + int *new_groupitem = + vim_realloc(stl_groupitem, sizeof(int) * new_len); + if (new_groupitem == NULL) + break; + stl_groupitem = new_groupitem; + + stl_hlrec_T *new_hlrec = vim_realloc(stl_hltab, + sizeof(stl_hlrec_T) * (new_len + 1)); + if (new_hlrec == NULL) + break; + stl_hltab = new_hlrec; + new_hlrec = vim_realloc(stl_tabtab, + sizeof(stl_hlrec_T) * (new_len + 1)); + if (new_hlrec == NULL) + break; + stl_tabtab = new_hlrec; + + int *new_separator_locs = vim_realloc(stl_separator_locations, + sizeof(int) * new_len); + if (new_separator_locs == NULL) + break; + stl_separator_locations = new_separator_locs;; + + stl_items_len = new_len; + } + + if (*s != '%') + prevchar_isflag = prevchar_isitem = FALSE; + + /* + * Handle up to the next '%' or the end. + */ + while (*s != NUL && *s != '%' && p + 1 < out + outlen) + *p++ = *s++; + if (*s == NUL || p + 1 >= out + outlen) + break; + + /* + * Handle one '%' item. + */ + s++; + if (*s == NUL) // ignore trailing % + break; + if (*s == '%') + { + if (p + 1 >= out + outlen) + break; + *p++ = *s++; + prevchar_isflag = prevchar_isitem = FALSE; + continue; + } + // STL_SEPARATE: Separation between items, filled with white space. + if (*s == STL_SEPARATE) + { + s++; + if (groupdepth > 0) + continue; + stl_items[curitem].stl_type = Separate; + stl_items[curitem++].stl_start = p; + continue; + } + if (*s == STL_TRUNCMARK) + { + s++; + stl_items[curitem].stl_type = Trunc; + stl_items[curitem++].stl_start = p; + continue; + } + if (*s == ')') + { + s++; + if (groupdepth < 1) + continue; + groupdepth--; + + t = stl_items[stl_groupitem[groupdepth]].stl_start; + *p = NUL; + l = vim_strsize(t); + if (curitem > stl_groupitem[groupdepth] + 1 + && stl_items[stl_groupitem[groupdepth]].stl_minwid == 0) + { + // remove group if all items are empty and highlight group + // doesn't change + group_start_userhl = group_end_userhl = 0; + for (n = stl_groupitem[groupdepth] - 1; n >= 0; n--) + { + if (stl_items[n].stl_type == Highlight) + { + group_start_userhl = group_end_userhl = + stl_items[n].stl_minwid; + break; + } + } + for (n = stl_groupitem[groupdepth] + 1; n < curitem; n++) + { + if (stl_items[n].stl_type == Normal) + break; + if (stl_items[n].stl_type == Highlight) + group_end_userhl = stl_items[n].stl_minwid; + } + if (n == curitem && group_start_userhl == group_end_userhl) + { + // empty group + p = t; + l = 0; + for (n = stl_groupitem[groupdepth] + 1; n < curitem; n++) + { + // do not use the highlighting from the removed group + if (stl_items[n].stl_type == Highlight) + stl_items[n].stl_type = Empty; + // adjust the start position of TabPage to the next + // item position + if (stl_items[n].stl_type == TabPage) + stl_items[n].stl_start = p; + } + } + } + if (l > stl_items[stl_groupitem[groupdepth]].stl_maxwid) + { + // truncate, remove n bytes of text at the start + if (has_mbyte) + { + // Find the first character that should be included. + n = 0; + while (l >= stl_items[stl_groupitem[groupdepth]].stl_maxwid) + { + l -= ptr2cells(t + n); + n += (*mb_ptr2len)(t + n); + } + } + else + n = (long)(p - t) - stl_items[stl_groupitem[groupdepth]] + .stl_maxwid + 1; + + *t = '<'; + mch_memmove(t + 1, t + n, (size_t)(p - (t + n))); + p = p - n + 1; + + // Fill up space left over by half a double-wide char. + while (++l < stl_items[stl_groupitem[groupdepth]].stl_minwid) + MB_CHAR2BYTES(fillchar, p); + + // correct the start of the items for the truncation + for (l = stl_groupitem[groupdepth] + 1; l < curitem; l++) + { + // Minus one for the leading '<' added above. + stl_items[l].stl_start -= n - 1; + if (stl_items[l].stl_start < t) + stl_items[l].stl_start = t; + } + } + else if (abs(stl_items[stl_groupitem[groupdepth]].stl_minwid) > l) + { + // fill + n = stl_items[stl_groupitem[groupdepth]].stl_minwid; + if (n < 0) + { + // fill by appending characters + n = 0 - n; + while (l++ < n && p + 1 < out + outlen) + MB_CHAR2BYTES(fillchar, p); + } + else + { + // fill by inserting characters + l = (n - l) * MB_CHAR2LEN(fillchar); + mch_memmove(t + l, t, (size_t)(p - t)); + if (p + l >= out + outlen) + l = (long)((out + outlen) - p - 1); + p += l; + for (n = stl_groupitem[groupdepth] + 1; n < curitem; n++) + stl_items[n].stl_start += l; + for ( ; l > 0; l--) + MB_CHAR2BYTES(fillchar, t); + } + } + continue; + } + minwid = 0; + maxwid = 9999; + zeropad = FALSE; + l = 1; + if (*s == '0') + { + s++; + zeropad = TRUE; + } + if (*s == '-') + { + s++; + l = -1; + } + if (VIM_ISDIGIT(*s)) + { + minwid = (int)getdigits(&s); + if (minwid < 0) // overflow + minwid = 0; + } + if (*s == STL_USER_HL) + { + stl_items[curitem].stl_type = Highlight; + stl_items[curitem].stl_start = p; + stl_items[curitem].stl_minwid = minwid > 9 ? 1 : minwid; + s++; + curitem++; + continue; + } + if (*s == STL_TABPAGENR || *s == STL_TABCLOSENR) + { + if (*s == STL_TABCLOSENR) + { + if (minwid == 0) + { + // %X ends the close label, go back to the previously + // define tab label nr. + for (n = curitem - 1; n >= 0; --n) + if (stl_items[n].stl_type == TabPage + && stl_items[n].stl_minwid >= 0) + { + minwid = stl_items[n].stl_minwid; + break; + } + } + else + // close nrs are stored as negative values + minwid = - minwid; + } + stl_items[curitem].stl_type = TabPage; + stl_items[curitem].stl_start = p; + stl_items[curitem].stl_minwid = minwid; + s++; + curitem++; + continue; + } + if (*s == '.') + { + s++; + if (VIM_ISDIGIT(*s)) + { + maxwid = (int)getdigits(&s); + if (maxwid <= 0) // overflow + maxwid = 50; + } + } + minwid = (minwid > 50 ? 50 : minwid) * l; + if (*s == '(') + { + stl_groupitem[groupdepth++] = curitem; + stl_items[curitem].stl_type = Group; + stl_items[curitem].stl_start = p; + stl_items[curitem].stl_minwid = minwid; + stl_items[curitem].stl_maxwid = maxwid; + s++; + curitem++; + continue; + } +#ifdef FEAT_EVAL + // Denotes end of expanded %{} block + if (*s == '}' && evaldepth > 0) + { + s++; + evaldepth--; + continue; + } +#endif + if (vim_strchr(STL_ALL, *s) == NULL) + { + if (*s == NUL) // can happen with "%0" + break; + s++; + continue; + } + opt = *s++; + + // OK - now for the real work + base = 'D'; + itemisflag = FALSE; + fillable = TRUE; + num = -1; + str = NULL; + switch (opt) + { + case STL_FILEPATH: + case STL_FULLPATH: + case STL_FILENAME: + fillable = FALSE; // don't change ' ' to fillchar + if (buf_spname(wp->w_buffer) != NULL) + vim_strncpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL - 1); + else + { + t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname + : wp->w_buffer->b_fname; + home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE); + } + trans_characters(NameBuff, MAXPATHL); + if (opt != STL_FILENAME) + str = NameBuff; + else + str = gettail(NameBuff); + break; + + case STL_VIM_EXPR: // '{' + { +#ifdef FEAT_EVAL + char_u *block_start = s - 1; +#endif + int reevaluate = (*s == '%'); + + if (reevaluate) + s++; + itemisflag = TRUE; + t = p; + while ((*s != '}' || (reevaluate && s[-1] != '%')) + && *s != NUL && p + 1 < out + outlen) + *p++ = *s++; + if (*s != '}') // missing '}' or out of space + break; + s++; + if (reevaluate) + p[-1] = 0; // remove the % at the end of %{% expr %} + else + *p = 0; + p = t; +#ifdef FEAT_EVAL + vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), + "%d", curbuf->b_fnum); + set_internal_string_var((char_u *)"g:actual_curbuf", buf_tmp); + vim_snprintf((char *)win_tmp, sizeof(win_tmp), "%d", curwin->w_id); + set_internal_string_var((char_u *)"g:actual_curwin", win_tmp); + + save_curbuf = curbuf; + save_curwin = curwin; + save_VIsual_active = VIsual_active; + curwin = wp; + curbuf = wp->w_buffer; + // Visual mode is only valid in the current window. + if (curwin != save_curwin) + VIsual_active = FALSE; + + str = eval_to_string_safe(p, use_sandbox, FALSE, FALSE); + + curwin = save_curwin; + curbuf = save_curbuf; + VIsual_active = save_VIsual_active; + do_unlet((char_u *)"g:actual_curbuf", TRUE); + do_unlet((char_u *)"g:actual_curwin", TRUE); + + if (str != NULL && *str != 0) + { + if (*skipdigits(str) == NUL) + { + num = atoi((char *)str); + VIM_CLEAR(str); + itemisflag = FALSE; + } + } + + // If the output of the expression needs to be evaluated + // replace the %{} block with the result of evaluation + if (reevaluate && str != NULL && *str != 0 + && strchr((const char *)str, '%') != NULL + && evaldepth < MAX_STL_EVAL_DEPTH) + { + size_t parsed_usefmt = (size_t)(block_start - usefmt); + size_t str_length = strlen((const char *)str); + size_t fmt_length = strlen((const char *)s); + size_t new_fmt_len = parsed_usefmt + + str_length + fmt_length + 3; + char_u *new_fmt = (char_u *)alloc(new_fmt_len * sizeof(char_u)); + char_u *new_fmt_p = new_fmt; + + new_fmt_p = (char_u *)memcpy(new_fmt_p, usefmt, parsed_usefmt) + + parsed_usefmt; + new_fmt_p = (char_u *)memcpy(new_fmt_p , str, str_length) + + str_length; + new_fmt_p = (char_u *)memcpy(new_fmt_p, "%}", 2) + 2; + new_fmt_p = (char_u *)memcpy(new_fmt_p , s, fmt_length) + + fmt_length; + *new_fmt_p = 0; + new_fmt_p = NULL; + + if (usefmt != fmt) + vim_free(usefmt); + VIM_CLEAR(str); + usefmt = new_fmt; + s = usefmt + parsed_usefmt; + evaldepth++; + continue; + } +#endif + break; + } + case STL_LINE: + num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) + ? 0L : (long)(wp->w_cursor.lnum); + break; + + case STL_NUMLINES: + num = wp->w_buffer->b_ml.ml_line_count; + break; + + case STL_COLUMN: + num = (State & MODE_INSERT) == 0 && empty_line + ? 0 : (int)wp->w_cursor.col + 1; + break; + + case STL_VIRTCOL: + case STL_VIRTCOL_ALT: + virtcol = wp->w_virtcol + 1; + // Don't display %V if it's the same as %c. + if (opt == STL_VIRTCOL_ALT + && (virtcol == (colnr_T)((State & MODE_INSERT) == 0 + && empty_line ? 0 : (int)wp->w_cursor.col + 1))) + break; + num = (long)virtcol; + break; + + case STL_PERCENTAGE: + num = (int)(((long)wp->w_cursor.lnum * 100L) / + (long)wp->w_buffer->b_ml.ml_line_count); + break; + + case STL_ALTPERCENT: + str = buf_tmp; + get_rel_pos(wp, str, TMPLEN); + break; + + case STL_SHOWCMD: + if (p_sc && STRCMP(opt_name, p_sloc) == 0) + str = showcmd_buf; + break; + + case STL_ARGLISTSTAT: + fillable = FALSE; + buf_tmp[0] = 0; + if (append_arg_number(wp, buf_tmp, (int)sizeof(buf_tmp), FALSE)) + str = buf_tmp; + break; + + case STL_KEYMAP: + fillable = FALSE; + if (get_keymap_str(wp, (char_u *)"<%s>", buf_tmp, TMPLEN)) + str = buf_tmp; + break; + case STL_PAGENUM: +#if defined(FEAT_PRINTER) || defined(FEAT_GUI_TABLINE) + num = printer_page_num; +#else + num = 0; +#endif + break; + + case STL_BUFNO: + num = wp->w_buffer->b_fnum; + break; + + case STL_OFFSET_X: + base = 'X'; + // FALLTHROUGH + case STL_OFFSET: +#ifdef FEAT_BYTEOFF + l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL); + num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 + ? 0L : l + 1 + ((State & MODE_INSERT) == 0 && empty_line + ? 0 : (int)wp->w_cursor.col); +#endif + break; + + case STL_BYTEVAL_X: + base = 'X'; + // FALLTHROUGH + case STL_BYTEVAL: + num = byteval; + if (num == NL) + num = 0; + else if (num == CAR && get_fileformat(wp->w_buffer) == EOL_MAC) + num = NL; + break; + + case STL_ROFLAG: + case STL_ROFLAG_ALT: + itemisflag = TRUE; + if (wp->w_buffer->b_p_ro) + str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]")); + break; + + case STL_HELPFLAG: + case STL_HELPFLAG_ALT: + itemisflag = TRUE; + if (wp->w_buffer->b_help) + str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP" + : _("[Help]")); + break; + + case STL_FILETYPE: + if (*wp->w_buffer->b_p_ft != NUL + && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3) + { + vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "[%s]", + wp->w_buffer->b_p_ft); + str = buf_tmp; + } + break; + + case STL_FILETYPE_ALT: + itemisflag = TRUE; + if (*wp->w_buffer->b_p_ft != NUL + && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) + { + vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), ",%s", + wp->w_buffer->b_p_ft); + for (t = buf_tmp; *t != 0; t++) + *t = TOUPPER_LOC(*t); + str = buf_tmp; + } + break; + +#if defined(FEAT_QUICKFIX) + case STL_PREVIEWFLAG: + case STL_PREVIEWFLAG_ALT: + itemisflag = TRUE; + if (wp->w_p_pvw) + str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV" + : _("[Preview]")); + break; + + case STL_QUICKFIX: + if (bt_quickfix(wp->w_buffer)) + str = (char_u *)(wp->w_llist_ref + ? _(msg_loclist) + : _(msg_qflist)); + break; +#endif + + case STL_MODIFIED: + case STL_MODIFIED_ALT: + itemisflag = TRUE; + switch ((opt == STL_MODIFIED_ALT) + + bufIsChanged(wp->w_buffer) * 2 + + (!wp->w_buffer->b_p_ma) * 4) + { + case 2: str = (char_u *)"[+]"; break; + case 3: str = (char_u *)",+"; break; + case 4: str = (char_u *)"[-]"; break; + case 5: str = (char_u *)",-"; break; + case 6: str = (char_u *)"[+-]"; break; + case 7: str = (char_u *)",+-"; break; + } + break; + + case STL_HIGHLIGHT: + t = s; + while (*s != '#' && *s != NUL) + ++s; + if (*s == '#') + { + stl_items[curitem].stl_type = Highlight; + stl_items[curitem].stl_start = p; + stl_items[curitem].stl_minwid = -syn_namen2id(t, (int)(s - t)); + curitem++; + } + if (*s != NUL) + ++s; + continue; + } + + stl_items[curitem].stl_start = p; + stl_items[curitem].stl_type = Normal; + if (str != NULL && *str) + { + t = str; + if (itemisflag) + { + if ((t[0] && t[1]) + && ((!prevchar_isitem && *t == ',') + || (prevchar_isflag && *t == ' '))) + t++; + prevchar_isflag = TRUE; + } + l = vim_strsize(t); + if (l > 0) + prevchar_isitem = TRUE; + if (l > maxwid) + { + while (l >= maxwid) + if (has_mbyte) + { + l -= ptr2cells(t); + t += (*mb_ptr2len)(t); + } + else + l -= byte2cells(*t++); + if (p + 1 >= out + outlen) + break; + *p++ = '<'; + } + if (minwid > 0) + { + for (; l < minwid && p + 1 < out + outlen; l++) + { + // Don't put a "-" in front of a digit. + if (l + 1 == minwid && fillchar == '-' && VIM_ISDIGIT(*t)) + *p++ = ' '; + else + MB_CHAR2BYTES(fillchar, p); + } + minwid = 0; + } + else + minwid *= -1; + for (; *t && p + 1 < out + outlen; t++) + { + // Change a space by fillchar, unless fillchar is '-' and a + // digit follows. + if (fillable && *t == ' ' + && (!VIM_ISDIGIT(*(t + 1)) || fillchar != '-')) + MB_CHAR2BYTES(fillchar, p); + else + *p++ = *t; + } + for (; l < minwid && p + 1 < out + outlen; l++) + MB_CHAR2BYTES(fillchar, p); + } + else if (num >= 0) + { + int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16)); + char_u nstr[20]; + + if (p + 20 >= out + outlen) + break; // not sufficient space + prevchar_isitem = TRUE; + t = nstr; + if (opt == STL_VIRTCOL_ALT) + { + *t++ = '-'; + minwid--; + } + *t++ = '%'; + if (zeropad) + *t++ = '0'; + *t++ = '*'; + *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd'); + *t = 0; + + for (n = num, l = 1; n >= nbase; n /= nbase) + l++; + if (opt == STL_VIRTCOL_ALT) + l++; + if (l > maxwid) + { + l += 2; + n = l - maxwid; + while (l-- > maxwid) + num /= nbase; + *t++ = '>'; + *t++ = '%'; + *t = t[-3]; + *++t = 0; + vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, + 0, num, n); + } + else + vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, + minwid, num); + p += STRLEN(p); + } + else + stl_items[curitem].stl_type = Empty; + + if (num >= 0 || (!itemisflag && str != NULL && *str != NUL)) + prevchar_isflag = FALSE; // Item not NULL, but not a flag + // + if (opt == STL_VIM_EXPR) + vim_free(str); + curitem++; + } + *p = NUL; + itemcnt = curitem; + +#ifdef FEAT_EVAL + if (usefmt != fmt) + vim_free(usefmt); +#endif + + width = vim_strsize(out); + if (maxwidth > 0 && width > maxwidth) + { + // Result is too long, must truncate somewhere. + l = 0; + if (itemcnt == 0) + s = out; + else + { + for ( ; l < itemcnt; l++) + if (stl_items[l].stl_type == Trunc) + { + // Truncate at %< item. + s = stl_items[l].stl_start; + break; + } + if (l == itemcnt) + { + // No %< item, truncate first item. + s = stl_items[0].stl_start; + l = 0; + } + } + + if (width - vim_strsize(s) >= maxwidth) + { + // Truncation mark is beyond max length + if (has_mbyte) + { + s = out; + width = 0; + for (;;) + { + width += ptr2cells(s); + if (width >= maxwidth) + break; + s += (*mb_ptr2len)(s); + } + // Fill up for half a double-wide character. + while (++width < maxwidth) + MB_CHAR2BYTES(fillchar, s); + } + else + s = out + maxwidth - 1; + for (l = 0; l < itemcnt; l++) + if (stl_items[l].stl_start > s) + break; + itemcnt = l; + *s++ = '>'; + *s = 0; + } + else + { + if (has_mbyte) + { + n = 0; + while (width >= maxwidth) + { + width -= ptr2cells(s + n); + n += (*mb_ptr2len)(s + n); + } + } + else + n = width - maxwidth + 1; + p = s + n; + STRMOVE(s + 1, p); + *s = '<'; + + // Fill up for half a double-wide character. + while (++width < maxwidth) + { + s = s + STRLEN(s); + MB_CHAR2BYTES(fillchar, s); + *s = NUL; + } + + --n; // count the '<' + for (; l < itemcnt; l++) + { + if (stl_items[l].stl_start - n >= s) + stl_items[l].stl_start -= n; + else + stl_items[l].stl_start = s; + } + } + width = maxwidth; + } + else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen) + { + // Find how many separators there are, which we will use when + // figuring out how many groups there are. + int num_separators = 0; + + for (l = 0; l < itemcnt; l++) + { + if (stl_items[l].stl_type == Separate) + { + // Create an array of the start location for each separator + // mark. + stl_separator_locations[num_separators] = l; + num_separators++; + } + } + + // If we have separated groups, then we deal with it now + if (num_separators) + { + int standard_spaces; + int final_spaces; + + standard_spaces = (maxwidth - width) / num_separators; + final_spaces = (maxwidth - width) - + standard_spaces * (num_separators - 1); + for (l = 0; l < num_separators; l++) + { + int dislocation = (l == (num_separators - 1)) ? + final_spaces : standard_spaces; + dislocation *= MB_CHAR2LEN(fillchar); + char_u *start = stl_items[stl_separator_locations[l]].stl_start; + char_u *seploc = start + dislocation; + STRMOVE(seploc, start); + for (s = start; s < seploc;) + MB_CHAR2BYTES(fillchar, s); + + for (int i = stl_separator_locations[l] + 1; i < itemcnt; i++) + stl_items[i].stl_start += dislocation; + } + + width = maxwidth; + } + } + + // Store the info about highlighting. + if (hltab != NULL) + { + *hltab = stl_hltab; + sp = stl_hltab; + for (l = 0; l < itemcnt; l++) + { + if (stl_items[l].stl_type == Highlight) + { + sp->start = stl_items[l].stl_start; + sp->userhl = stl_items[l].stl_minwid; + sp++; + } + } + sp->start = NULL; + sp->userhl = 0; + } + + // Store the info about tab pages labels. + if (tabtab != NULL) + { + *tabtab = stl_tabtab; + sp = stl_tabtab; + for (l = 0; l < itemcnt; l++) + { + if (stl_items[l].stl_type == TabPage) + { + sp->start = stl_items[l].stl_start; + sp->userhl = stl_items[l].stl_minwid; + sp++; + } + } + sp->start = NULL; + sp->userhl = 0; + } + + redraw_not_allowed = save_redraw_not_allowed; + + // A user function may reset KeyTyped, restore it. + KeyTyped = save_KeyTyped; + + // Check for an error. If there is one the display will be messed up and + // might loop redrawing. Avoid that by making the corresponding option + // empty. + // TODO: find out why using called_emsg_before makes tests fail, does it + // matter? + // if (called_emsg > called_emsg_before) + if (did_emsg > did_emsg_before) + set_string_option_direct(opt_name, -1, (char_u *)"", + OPT_FREE | opt_scope, SID_ERROR); + + return width; +} +#endif // FEAT_STL_OPT + +/* + * Get relative cursor position in window into "buf[buflen]", in the form 99%, + * using "Top", "Bot" or "All" when appropriate. + */ + void +get_rel_pos( + win_T *wp, + char_u *buf, + int buflen) +{ + long above; // number of lines above window + long below; // number of lines below window + + if (buflen < 3) // need at least 3 chars for writing + return; + above = wp->w_topline - 1; +#ifdef FEAT_DIFF + above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill; + if (wp->w_topline == 1 && wp->w_topfill >= 1) + above = 0; // All buffer lines are displayed and there is an + // indication of filler lines, that can be considered + // seeing all lines. +#endif + below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1; + if (below <= 0) + vim_strncpy(buf, (char_u *)(above == 0 ? _("All") : _("Bot")), + (size_t)(buflen - 1)); + else if (above <= 0) + vim_strncpy(buf, (char_u *)_("Top"), (size_t)(buflen - 1)); + else + vim_snprintf((char *)buf, (size_t)buflen, "%2d%%", above > 1000000L + ? (int)(above / ((above + below) / 100L)) + : (int)(above * 100L / (above + below))); +} + +/* + * Append (file 2 of 8) to "buf[buflen]", if editing more than one file. + * Return TRUE if it was appended. + */ + static int +append_arg_number( + win_T *wp, + char_u *buf, + int buflen, + int add_file) // Add "file" before the arg number +{ + char_u *p; + + if (ARGCOUNT <= 1) // nothing to do + return FALSE; + + p = buf + STRLEN(buf); // go to the end of the buffer + if (p - buf + 35 >= buflen) // getting too long + return FALSE; + *p++ = ' '; + *p++ = '('; + if (add_file) + { + STRCPY(p, "file "); + p += 5; + } + vim_snprintf((char *)p, (size_t)(buflen - (p - buf)), + wp->w_arg_idx_invalid ? "(%d) of %d)" + : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT); + return TRUE; +} + +/* + * If fname is not a full path, make it a full path. + * Returns pointer to allocated memory (NULL for failure). + */ + char_u * +fix_fname(char_u *fname) +{ + /* + * Force expanding the path always for Unix, because symbolic links may + * mess up the full path name, even though it starts with a '/'. + * Also expand when there is ".." in the file name, try to remove it, + * because "c:/src/../README" is equal to "c:/README". + * Similarly "c:/src//file" is equal to "c:/src/file". + * For MS-Windows also expand names like "longna~1" to "longname". + */ +#ifdef UNIX + return FullName_save(fname, TRUE); +#else + if (!vim_isAbsName(fname) + || strstr((char *)fname, "..") != NULL + || strstr((char *)fname, "//") != NULL +# ifdef BACKSLASH_IN_FILENAME + || strstr((char *)fname, "\\\\") != NULL +# endif +# if defined(MSWIN) + || vim_strchr(fname, '~') != NULL +# endif + ) + return FullName_save(fname, FALSE); + + fname = vim_strsave(fname); + +# ifdef USE_FNAME_CASE + if (fname != NULL) + fname_case(fname, 0); // set correct case for file name +# endif + + return fname; +#endif +} + +/* + * Make "*ffname" a full file name, set "*sfname" to "*ffname" if not NULL. + * "*ffname" becomes a pointer to allocated memory (or NULL). + * When resolving a link both "*sfname" and "*ffname" will point to the same + * allocated memory. + * The "*ffname" and "*sfname" pointer values on call will not be freed. + * Note that the resulting "*ffname" pointer should be considered not allocated. + */ + void +fname_expand( + buf_T *buf UNUSED, + char_u **ffname, + char_u **sfname) +{ + if (*ffname == NULL) // no file name given, nothing to do + return; + if (*sfname == NULL) // no short file name given, use ffname + *sfname = *ffname; + *ffname = fix_fname(*ffname); // expand to full path + +#ifdef FEAT_SHORTCUT + if (!buf->b_p_bin) + { + char_u *rfname; + + // If the file name is a shortcut file, use the file it links to. + rfname = mch_resolve_path(*ffname, FALSE); + if (rfname != NULL) + { + vim_free(*ffname); + *ffname = rfname; + *sfname = rfname; + } + } +#endif +} + +/* + * Open a window for a number of buffers. + */ + void +ex_buffer_all(exarg_T *eap) +{ + buf_T *buf; + win_T *wp, *wpnext; + int split_ret = OK; + int p_ea_save; + int open_wins = 0; + int r; + int count; // Maximum number of windows to open. + int all; // When TRUE also load inactive buffers. + int had_tab = cmdmod.cmod_tab; + tabpage_T *tpnext; + + if (eap->addr_count == 0) // make as many windows as possible + count = 9999; + else + count = eap->line2; // make as many windows as specified + if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide) + all = FALSE; + else + all = TRUE; + + // Stop Visual mode, the cursor and "VIsual" may very well be invalid after + // switching to another buffer. + reset_VIsual_and_resel(); + + setpcmark(); + +#ifdef FEAT_GUI + need_mouse_correct = TRUE; +#endif + + /* + * Close superfluous windows (two windows for the same buffer). + * Also close windows that are not full-width. + */ + if (had_tab > 0) + goto_tabpage_tp(first_tabpage, TRUE, TRUE); + for (;;) + { + tpnext = curtab->tp_next; + for (wp = firstwin; wp != NULL; wp = wpnext) + { + wpnext = wp->w_next; + if ((wp->w_buffer->b_nwindows > 1 + || ((cmdmod.cmod_split & WSP_VERT) + ? wp->w_height + wp->w_status_height < Rows - p_ch + - tabline_height() + : wp->w_width != Columns) + || (had_tab > 0 && wp != firstwin)) + && !ONE_WINDOW + && !(wp->w_closing || wp->w_buffer->b_locked > 0) + && !win_unlisted(wp)) + { + if (win_close(wp, FALSE) == FAIL) + break; + // Just in case an autocommand does something strange with + // windows: start all over... + wpnext = firstwin; + tpnext = first_tabpage; + open_wins = 0; + } + else + ++open_wins; + } + + // Without the ":tab" modifier only do the current tab page. + if (had_tab == 0 || tpnext == NULL) + break; + goto_tabpage_tp(tpnext, TRUE, TRUE); + } + + /* + * Go through the buffer list. When a buffer doesn't have a window yet, + * open one. Otherwise move the window to the right position. + * Watch out for autocommands that delete buffers or windows! + */ + // Don't execute Win/Buf Enter/Leave autocommands here. + ++autocmd_no_enter; + win_enter(lastwin, FALSE); + ++autocmd_no_leave; + for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next) + { + // Check if this buffer needs a window + if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl) + continue; + + if (had_tab != 0) + { + // With the ":tab" modifier don't move the window. + if (buf->b_nwindows > 0) + wp = lastwin; // buffer has a window, skip it + else + wp = NULL; + } + else + { + // Check if this buffer already has a window + FOR_ALL_WINDOWS(wp) + if (wp->w_buffer == buf) + break; + // If the buffer already has a window, move it + if (wp != NULL) + win_move_after(wp, curwin); + } + + if (wp == NULL && split_ret == OK) + { + bufref_T bufref; + + set_bufref(&bufref, buf); + + // Split the window and put the buffer in it + p_ea_save = p_ea; + p_ea = TRUE; // use space from all windows + split_ret = win_split(0, WSP_ROOM | WSP_BELOW); + ++open_wins; + p_ea = p_ea_save; + if (split_ret == FAIL) + continue; + + // Open the buffer in this window. + swap_exists_action = SEA_DIALOG; + set_curbuf(buf, DOBUF_GOTO); + if (!bufref_valid(&bufref)) + { + // autocommands deleted the buffer!!! + swap_exists_action = SEA_NONE; + break; + } + if (swap_exists_action == SEA_QUIT) + { +#if defined(FEAT_EVAL) + cleanup_T cs; + + // Reset the error/interrupt/exception state here so that + // aborting() returns FALSE when closing a window. + enter_cleanup(&cs); +#endif + + // User selected Quit at ATTENTION prompt; close this window. + win_close(curwin, TRUE); + --open_wins; + swap_exists_action = SEA_NONE; + swap_exists_did_quit = TRUE; + +#if defined(FEAT_EVAL) + // Restore the error/interrupt/exception state if not + // discarded by a new aborting error, interrupt, or uncaught + // exception. + leave_cleanup(&cs); +#endif + } + else + handle_swap_exists(NULL); + } + + ui_breakcheck(); + if (got_int) + { + (void)vgetc(); // only break the file loading, not the rest + break; + } +#ifdef FEAT_EVAL + // Autocommands deleted the buffer or aborted script processing!!! + if (aborting()) + break; +#endif + // When ":tab" was used open a new tab for a new window repeatedly. + if (had_tab > 0 && tabpage_index(NULL) <= p_tpm) + cmdmod.cmod_tab = 9999; + } + --autocmd_no_enter; + win_enter(firstwin, FALSE); // back to first window + --autocmd_no_leave; + + /* + * Close superfluous windows. + */ + for (wp = lastwin; open_wins > count; ) + { + r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer) + || autowrite(wp->w_buffer, FALSE) == OK); + if (!win_valid(wp)) + { + // BufWrite Autocommands made the window invalid, start over + wp = lastwin; + } + else if (r) + { + win_close(wp, !buf_hide(wp->w_buffer)); + --open_wins; + wp = lastwin; + } + else + { + wp = wp->w_prev; + if (wp == NULL) + break; + } + } +} + + +static int chk_modeline(linenr_T, int); + +/* + * do_modelines() - process mode lines for the current file + * + * "flags" can be: + * OPT_WINONLY only set options local to window + * OPT_NOWIN don't set options local to window + * + * Returns immediately if the "ml" option isn't set. + */ + void +do_modelines(int flags) +{ + linenr_T lnum; + int nmlines; + static int entered = 0; + + if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0) + return; + + // Disallow recursive entry here. Can happen when executing a modeline + // triggers an autocommand, which reloads modelines with a ":do". + if (entered) + return; + + ++entered; + for (lnum = 1; curbuf->b_p_ml && lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines; + ++lnum) + if (chk_modeline(lnum, flags) == FAIL) + nmlines = 0; + + for (lnum = curbuf->b_ml.ml_line_count; curbuf->b_p_ml && lnum > 0 && lnum > nmlines + && lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum) + if (chk_modeline(lnum, flags) == FAIL) + nmlines = 0; + --entered; +} + +#include "version.h" // for version number + +/* + * chk_modeline() - check a single line for a mode string + * Return FAIL if an error encountered. + */ + static int +chk_modeline( + linenr_T lnum, + int flags) // Same as for do_modelines(). +{ + char_u *s; + char_u *e; + char_u *linecopy; // local copy of any modeline found + int prev; + int vers; + int end; + int retval = OK; + sctx_T save_current_sctx; + + ESTACK_CHECK_DECLARATION + + prev = -1; + for (s = ml_get(lnum); *s != NUL; ++s) + { + if (prev == -1 || vim_isspace(prev)) + { + if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0) + || STRNCMP(s, "vi:", (size_t)3) == 0) + break; + // Accept both "vim" and "Vim". + if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm') + { + if (s[3] == '<' || s[3] == '=' || s[3] == '>') + e = s + 4; + else + e = s + 3; + vers = getdigits(&e); + if (*e == ':' + && (s[0] != 'V' + || STRNCMP(skipwhite(e + 1), "set", 3) == 0) + && (s[3] == ':' + || (VIM_VERSION_100 >= vers && isdigit(s[3])) + || (VIM_VERSION_100 < vers && s[3] == '<') + || (VIM_VERSION_100 > vers && s[3] == '>') + || (VIM_VERSION_100 == vers && s[3] == '='))) + break; + } + } + prev = *s; + } + + if (*s) + { + do // skip over "ex:", "vi:" or "vim:" + ++s; + while (s[-1] != ':'); + + s = linecopy = vim_strsave(s); // copy the line, it will change + if (linecopy == NULL) + return FAIL; + + // prepare for emsg() + estack_push(ETYPE_MODELINE, (char_u *)"modelines", lnum); + ESTACK_CHECK_SETUP + + end = FALSE; + while (end == FALSE) + { + s = skipwhite(s); + if (*s == NUL) + break; + + /* + * Find end of set command: ':' or end of line. + * Skip over "\:", replacing it with ":". + */ + for (e = s; *e != ':' && *e != NUL; ++e) + if (e[0] == '\\' && e[1] == ':') + STRMOVE(e, e + 1); + if (*e == NUL) + end = TRUE; + + /* + * If there is a "set" command, require a terminating ':' and + * ignore the stuff after the ':'. + * "vi:set opt opt opt: foo" -- foo not interpreted + * "vi:opt opt opt: foo" -- foo interpreted + * Accept "se" for compatibility with Elvis. + */ + if (STRNCMP(s, "set ", (size_t)4) == 0 + || STRNCMP(s, "se ", (size_t)3) == 0) + { + if (*e != ':') // no terminating ':'? + break; + end = TRUE; + s = vim_strchr(s, ' ') + 1; + } + *e = NUL; // truncate the set command + + if (*s != NUL) // skip over an empty "::" + { + int secure_save = secure; + + save_current_sctx = current_sctx; + current_sctx.sc_version = 1; +#ifdef FEAT_EVAL + current_sctx.sc_sid = SID_MODELINE; + current_sctx.sc_seq = 0; + current_sctx.sc_lnum = lnum; +#endif + + // Make sure no risky things are executed as a side effect. + secure = 1; + + retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags); + + secure = secure_save; + current_sctx = save_current_sctx; + if (retval == FAIL) // stop if error found + break; + } + s = e + 1; // advance to next part + } + + ESTACK_CHECK_NOW + estack_pop(); + vim_free(linecopy); + } + return retval; +} + +/* + * Return TRUE if "buf" is a normal buffer, 'buftype' is empty. + */ + int +bt_normal(buf_T *buf) +{ + return buf != NULL && buf->b_p_bt[0] == NUL; +} + +/* + * Return TRUE if "buf" is the quickfix buffer. + */ + int +bt_quickfix(buf_T *buf UNUSED) +{ +#ifdef FEAT_QUICKFIX + return buf != NULL && buf->b_p_bt[0] == 'q'; +#else + return FALSE; +#endif +} + +/* + * Return TRUE if "buf" is a terminal buffer. + */ + int +bt_terminal(buf_T *buf UNUSED) +{ +#if defined(FEAT_TERMINAL) + return buf != NULL && buf->b_p_bt[0] == 't'; +#else + return FALSE; +#endif +} + +/* + * Return TRUE if "buf" is a help buffer. + */ + int +bt_help(buf_T *buf) +{ + return buf != NULL && buf->b_help; +} + +/* + * Return TRUE if "buf" is a prompt buffer. + */ + int +bt_prompt(buf_T *buf) +{ + return buf != NULL && buf->b_p_bt[0] == 'p' && buf->b_p_bt[1] == 'r'; +} + +#if defined(FEAT_PROP_POPUP) || defined(PROTO) +/* + * Return TRUE if "buf" is a buffer for a popup window. + */ + int +bt_popup(buf_T *buf) +{ + return buf != NULL && buf->b_p_bt != NULL + && buf->b_p_bt[0] == 'p' && buf->b_p_bt[1] == 'o'; +} +#endif + +/* + * Return TRUE if "buf" is a "nofile", "acwrite", "terminal" or "prompt" + * buffer. This means the buffer name may not be a file name, at least not for + * writing the buffer. + */ + int +bt_nofilename(buf_T *buf) +{ + return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') + || buf->b_p_bt[0] == 'a' + || buf->b_p_bt[0] == 't' + || buf->b_p_bt[0] == 'p'); +} + +/* + * Return TRUE if "buf" is a "nofile", "quickfix", "terminal" or "prompt" + * buffer. This means the buffer is not to be read from a file. + */ + static int +bt_nofileread(buf_T *buf) +{ + return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') + || buf->b_p_bt[0] == 't' + || buf->b_p_bt[0] == 'q' + || buf->b_p_bt[0] == 'p'); +} + +#if defined(FEAT_QUICKFIX) || defined(PROTO) +/* + * Return TRUE if "buf" has 'buftype' set to "nofile". + */ + int +bt_nofile(buf_T *buf) +{ + return buf != NULL && buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f'; +} +#endif + +/* + * Return TRUE if "buf" is a "nowrite", "nofile", "terminal", "prompt", or + * "popup" buffer. + */ + int +bt_dontwrite(buf_T *buf) +{ + return buf != NULL && (buf->b_p_bt[0] == 'n' + || buf->b_p_bt[0] == 't' + || buf->b_p_bt[0] == 'p'); +} + + int +bt_dontwrite_msg(buf_T *buf) +{ + if (bt_dontwrite(buf)) + { + emsg(_(e_cannot_write_buftype_option_is_set)); + return TRUE; + } + return FALSE; +} + +/* + * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide" + * and 'bufhidden'. + */ + int +buf_hide(buf_T *buf) +{ + // 'bufhidden' overrules 'hidden' and ":hide", check it first + switch (buf->b_p_bh[0]) + { + case 'u': // "unload" + case 'w': // "wipe" + case 'd': return FALSE; // "delete" + case 'h': return TRUE; // "hide" + } + return (p_hid || (cmdmod.cmod_flags & CMOD_HIDE)); +} + +/* + * Return special buffer name. + * Returns NULL when the buffer has a normal file name. + */ + char_u * +buf_spname(buf_T *buf) +{ +#if defined(FEAT_QUICKFIX) + if (bt_quickfix(buf)) + { + /* + * Differentiate between the quickfix and location list buffers using + * the buffer number stored in the global quickfix stack. + */ + if (buf->b_fnum == qf_stack_get_bufnr()) + return (char_u *)_(msg_qflist); + else + return (char_u *)_(msg_loclist); + } +#endif + + // There is no _file_ when 'buftype' is "nofile", b_sfname + // contains the name as specified by the user. + if (bt_nofilename(buf)) + { +#ifdef FEAT_TERMINAL + if (buf->b_term != NULL) + return term_get_status_text(buf->b_term); +#endif + if (buf->b_fname != NULL) + return buf->b_fname; +#ifdef FEAT_JOB_CHANNEL + if (bt_prompt(buf)) + return (char_u *)_("[Prompt]"); +#endif +#ifdef FEAT_PROP_POPUP + if (bt_popup(buf)) + return (char_u *)_("[Popup]"); +#endif + return (char_u *)_("[Scratch]"); + } + + if (buf->b_fname == NULL) + return buf_get_fname(buf); + return NULL; +} + +/* + * Get "buf->b_fname", use "[No Name]" if it is NULL. + */ + char_u * +buf_get_fname(buf_T *buf) +{ + if (buf->b_fname == NULL) + return (char_u *)_("[No Name]"); + return buf->b_fname; +} + +/* + * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed. + */ + void +set_buflisted(int on) +{ + if (on == curbuf->b_p_bl) + return; + + curbuf->b_p_bl = on; + if (on) + apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf); + else + apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf); +} + +/* + * Read the file for "buf" again and check if the contents changed. + * Return TRUE if it changed or this could not be checked. + */ + int +buf_contents_changed(buf_T *buf) +{ + buf_T *newbuf; + int differ = TRUE; + linenr_T lnum; + aco_save_T aco; + exarg_T ea; + + // Allocate a buffer without putting it in the buffer list. + newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY); + if (newbuf == NULL) + return TRUE; + + // Force the 'fileencoding' and 'fileformat' to be equal. + if (prep_exarg(&ea, buf) == FAIL) + { + wipe_buffer(newbuf, FALSE); + return TRUE; + } + + // Set curwin/curbuf to buf and save a few things. + aucmd_prepbuf(&aco, newbuf); + if (curbuf != newbuf) + { + // Failed to find a window for "newbuf". + wipe_buffer(newbuf, FALSE); + return TRUE; + } + + if (ml_open(curbuf) == OK + && readfile(buf->b_ffname, buf->b_fname, + (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, + &ea, READ_NEW | READ_DUMMY) == OK) + { + // compare the two files line by line + if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count) + { + differ = FALSE; + for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) + if (STRCMP(ml_get_buf(buf, lnum, FALSE), ml_get(lnum)) != 0) + { + differ = TRUE; + break; + } + } + } + vim_free(ea.cmd); + + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + + if (curbuf != newbuf) // safety check + wipe_buffer(newbuf, FALSE); + + return differ; +} + +/* + * Wipe out a buffer and decrement the last buffer number if it was used for + * this buffer. Call this to wipe out a temp buffer that does not contain any + * marks. + */ + void +wipe_buffer( + buf_T *buf, + int aucmd) // When TRUE trigger autocommands. +{ + if (buf->b_fnum == top_file_num - 1) + --top_file_num; + + if (!aucmd) // Don't trigger BufDelete autocommands here. + block_autocmds(); + + close_buffer(NULL, buf, DOBUF_WIPE, FALSE, TRUE); + + if (!aucmd) + unblock_autocmds(); +} diff --git a/src/bufwrite.c b/src/bufwrite.c new file mode 100644 index 0000000..03a83b5 --- /dev/null +++ b/src/bufwrite.c @@ -0,0 +1,2638 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * bufwrite.c: functions for writing a buffer + */ + +#include "vim.h" + +#if defined(HAVE_UTIME) && defined(HAVE_UTIME_H) +# include // for struct utimbuf +#endif + +#define SMALLBUFSIZE 256 // size of emergency write buffer + +/* + * Structure to pass arguments from buf_write() to buf_write_bytes(). + */ +struct bw_info +{ + int bw_fd; // file descriptor + char_u *bw_buf; // buffer with data to be written + int bw_len; // length of data + int bw_flags; // FIO_ flags +#ifdef FEAT_CRYPT + buf_T *bw_buffer; // buffer being written + int bw_finish; // finish encrypting +#endif + char_u bw_rest[CONV_RESTLEN]; // not converted bytes + int bw_restlen; // nr of bytes in bw_rest[] + int bw_first; // first write call + char_u *bw_conv_buf; // buffer for writing converted chars + size_t bw_conv_buflen; // size of bw_conv_buf + int bw_conv_error; // set for conversion error + linenr_T bw_conv_error_lnum; // first line with error or zero + linenr_T bw_start_lnum; // line number at start of buffer +#ifdef USE_ICONV + iconv_t bw_iconv_fd; // descriptor for iconv() or -1 +#endif +}; + +/* + * Convert a Unicode character to bytes. + * Return TRUE for an error, FALSE when it's OK. + */ + static int +ucs2bytes( + unsigned c, // in: character + char_u **pp, // in/out: pointer to result + int flags) // FIO_ flags +{ + char_u *p = *pp; + int error = FALSE; + int cc; + + + if (flags & FIO_UCS4) + { + if (flags & FIO_ENDIAN_L) + { + *p++ = c; + *p++ = (c >> 8); + *p++ = (c >> 16); + *p++ = (c >> 24); + } + else + { + *p++ = (c >> 24); + *p++ = (c >> 16); + *p++ = (c >> 8); + *p++ = c; + } + } + else if (flags & (FIO_UCS2 | FIO_UTF16)) + { + if (c >= 0x10000) + { + if (flags & FIO_UTF16) + { + // Make two words, ten bits of the character in each. First + // word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff + c -= 0x10000; + if (c >= 0x100000) + error = TRUE; + cc = ((c >> 10) & 0x3ff) + 0xd800; + if (flags & FIO_ENDIAN_L) + { + *p++ = cc; + *p++ = ((unsigned)cc >> 8); + } + else + { + *p++ = ((unsigned)cc >> 8); + *p++ = cc; + } + c = (c & 0x3ff) + 0xdc00; + } + else + error = TRUE; + } + if (flags & FIO_ENDIAN_L) + { + *p++ = c; + *p++ = (c >> 8); + } + else + { + *p++ = (c >> 8); + *p++ = c; + } + } + else // Latin1 + { + if (c >= 0x100) + { + error = TRUE; + *p++ = 0xBF; + } + else + *p++ = c; + } + + *pp = p; + return error; +} + +/* + * Call write() to write a number of bytes to the file. + * Handles encryption and 'encoding' conversion. + * + * Return FAIL for failure, OK otherwise. + */ + static int +buf_write_bytes(struct bw_info *ip) +{ + int wlen; + char_u *buf = ip->bw_buf; // data to write + int len = ip->bw_len; // length of data + int flags = ip->bw_flags; // extra flags + + // Skip conversion when writing the crypt magic number or the BOM. + if (!(flags & FIO_NOCONVERT)) + { + char_u *p; + unsigned c; + int n; + + if (flags & FIO_UTF8) + { + // Convert latin1 in the buffer to UTF-8 in the file. + p = ip->bw_conv_buf; // translate to buffer + for (wlen = 0; wlen < len; ++wlen) + p += utf_char2bytes(buf[wlen], p); + buf = ip->bw_conv_buf; + len = (int)(p - ip->bw_conv_buf); + } + else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) + { + // Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or + // Latin1 chars in the file. + if (flags & FIO_LATIN1) + p = buf; // translate in-place (can only get shorter) + else + p = ip->bw_conv_buf; // translate to buffer + for (wlen = 0; wlen < len; wlen += n) + { + if (wlen == 0 && ip->bw_restlen != 0) + { + int l; + + // Use remainder of previous call. Append the start of + // buf[] to get a full sequence. Might still be too + // short! + l = CONV_RESTLEN - ip->bw_restlen; + if (l > len) + l = len; + mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l); + n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l); + if (n > ip->bw_restlen + len) + { + // We have an incomplete byte sequence at the end to + // be written. We can't convert it without the + // remaining bytes. Keep them for the next call. + if (ip->bw_restlen + len > CONV_RESTLEN) + return FAIL; + ip->bw_restlen += len; + break; + } + if (n > 1) + c = utf_ptr2char(ip->bw_rest); + else + c = ip->bw_rest[0]; + if (n >= ip->bw_restlen) + { + n -= ip->bw_restlen; + ip->bw_restlen = 0; + } + else + { + ip->bw_restlen -= n; + mch_memmove(ip->bw_rest, ip->bw_rest + n, + (size_t)ip->bw_restlen); + n = 0; + } + } + else + { + n = utf_ptr2len_len(buf + wlen, len - wlen); + if (n > len - wlen) + { + // We have an incomplete byte sequence at the end to + // be written. We can't convert it without the + // remaining bytes. Keep them for the next call. + if (len - wlen > CONV_RESTLEN) + return FAIL; + ip->bw_restlen = len - wlen; + mch_memmove(ip->bw_rest, buf + wlen, + (size_t)ip->bw_restlen); + break; + } + if (n > 1) + c = utf_ptr2char(buf + wlen); + else + c = buf[wlen]; + } + + if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) + { + ip->bw_conv_error = TRUE; + ip->bw_conv_error_lnum = ip->bw_start_lnum; + } + if (c == NL) + ++ip->bw_start_lnum; + } + if (flags & FIO_LATIN1) + len = (int)(p - buf); + else + { + buf = ip->bw_conv_buf; + len = (int)(p - ip->bw_conv_buf); + } + } + +#ifdef MSWIN + else if (flags & FIO_CODEPAGE) + { + // Convert UTF-8 or codepage to UCS-2 and then to MS-Windows + // codepage. + char_u *from; + size_t fromlen; + char_u *to; + int u8c; + BOOL bad = FALSE; + int needed; + + if (ip->bw_restlen > 0) + { + // Need to concatenate the remainder of the previous call and + // the bytes of the current call. Use the end of the + // conversion buffer for this. + fromlen = len + ip->bw_restlen; + from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; + mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen); + mch_memmove(from + ip->bw_restlen, buf, (size_t)len); + } + else + { + from = buf; + fromlen = len; + } + + to = ip->bw_conv_buf; + if (enc_utf8) + { + // Convert from UTF-8 to UCS-2, to the start of the buffer. + // The buffer has been allocated to be big enough. + while (fromlen > 0) + { + n = (int)utf_ptr2len_len(from, (int)fromlen); + if (n > (int)fromlen) // incomplete byte sequence + break; + u8c = utf_ptr2char(from); + *to++ = (u8c & 0xff); + *to++ = (u8c >> 8); + fromlen -= n; + from += n; + } + + // Copy remainder to ip->bw_rest[] to be used for the next + // call. + if (fromlen > CONV_RESTLEN) + { + // weird overlong sequence + ip->bw_conv_error = TRUE; + return FAIL; + } + mch_memmove(ip->bw_rest, from, fromlen); + ip->bw_restlen = (int)fromlen; + } + else + { + // Convert from enc_codepage to UCS-2, to the start of the + // buffer. The buffer has been allocated to be big enough. + ip->bw_restlen = 0; + needed = MultiByteToWideChar(enc_codepage, + MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen, + NULL, 0); + if (needed == 0) + { + // When conversion fails there may be a trailing byte. + needed = MultiByteToWideChar(enc_codepage, + MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen - 1, + NULL, 0); + if (needed == 0) + { + // Conversion doesn't work. + ip->bw_conv_error = TRUE; + return FAIL; + } + // Save the trailing byte for the next call. + ip->bw_rest[0] = from[fromlen - 1]; + ip->bw_restlen = 1; + } + needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS, + (LPCSTR)from, (int)(fromlen - ip->bw_restlen), + (LPWSTR)to, needed); + if (needed == 0) + { + // Safety check: Conversion doesn't work. + ip->bw_conv_error = TRUE; + return FAIL; + } + to += needed * 2; + } + + fromlen = to - ip->bw_conv_buf; + buf = to; +# ifdef CP_UTF8 // VC 4.1 doesn't define CP_UTF8 + if (FIO_GET_CP(flags) == CP_UTF8) + { + // Convert from UCS-2 to UTF-8, using the remainder of the + // conversion buffer. Fails when out of space. + for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2) + { + u8c = *from++; + u8c += (*from++ << 8); + to += utf_char2bytes(u8c, to); + if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen) + { + ip->bw_conv_error = TRUE; + return FAIL; + } + } + len = (int)(to - buf); + } + else +# endif + { + // Convert from UCS-2 to the codepage, using the remainder of + // the conversion buffer. If the conversion uses the default + // character "0", the data doesn't fit in this encoding, so + // fail. + len = WideCharToMultiByte(FIO_GET_CP(flags), 0, + (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR), + (LPSTR)to, (int)(ip->bw_conv_buflen - fromlen), 0, + &bad); + if (bad) + { + ip->bw_conv_error = TRUE; + return FAIL; + } + } + } +#endif + +#ifdef MACOS_CONVERT + else if (flags & FIO_MACROMAN) + { + // Convert UTF-8 or latin1 to Apple MacRoman. + char_u *from; + size_t fromlen; + + if (ip->bw_restlen > 0) + { + // Need to concatenate the remainder of the previous call and + // the bytes of the current call. Use the end of the + // conversion buffer for this. + fromlen = len + ip->bw_restlen; + from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; + mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen); + mch_memmove(from + ip->bw_restlen, buf, (size_t)len); + } + else + { + from = buf; + fromlen = len; + } + + if (enc2macroman(from, fromlen, + ip->bw_conv_buf, &len, ip->bw_conv_buflen, + ip->bw_rest, &ip->bw_restlen) == FAIL) + { + ip->bw_conv_error = TRUE; + return FAIL; + } + buf = ip->bw_conv_buf; + } +#endif + +#ifdef USE_ICONV + if (ip->bw_iconv_fd != (iconv_t)-1) + { + const char *from; + size_t fromlen; + char *to; + size_t tolen; + + // Convert with iconv(). + if (ip->bw_restlen > 0) + { + char *fp; + + // Need to concatenate the remainder of the previous call and + // the bytes of the current call. Use the end of the + // conversion buffer for this. + fromlen = len + ip->bw_restlen; + fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; + mch_memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen); + mch_memmove(fp + ip->bw_restlen, buf, (size_t)len); + from = fp; + tolen = ip->bw_conv_buflen - fromlen; + } + else + { + from = (const char *)buf; + fromlen = len; + tolen = ip->bw_conv_buflen; + } + to = (char *)ip->bw_conv_buf; + + if (ip->bw_first) + { + size_t save_len = tolen; + + // output the initial shift state sequence + (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen); + + // There is a bug in iconv() on Linux (which appears to be + // wide-spread) which sets "to" to NULL and messes up "tolen". + if (to == NULL) + { + to = (char *)ip->bw_conv_buf; + tolen = save_len; + } + ip->bw_first = FALSE; + } + + // If iconv() has an error or there is not enough room, fail. + if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen) + == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL) + || fromlen > CONV_RESTLEN) + { + ip->bw_conv_error = TRUE; + return FAIL; + } + + // copy remainder to ip->bw_rest[] to be used for the next call. + if (fromlen > 0) + mch_memmove(ip->bw_rest, (void *)from, fromlen); + ip->bw_restlen = (int)fromlen; + + buf = ip->bw_conv_buf; + len = (int)((char_u *)to - ip->bw_conv_buf); + } +#endif + } + + if (ip->bw_fd < 0) + // Only checking conversion, which is OK if we get here. + return OK; + +#ifdef FEAT_CRYPT + if (flags & FIO_ENCRYPTED) + { + // Encrypt the data. Do it in-place if possible, otherwise use an + // allocated buffer. +# ifdef CRYPT_NOT_INPLACE + if (crypt_works_inplace(ip->bw_buffer->b_cryptstate)) + { +# endif + crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len, + ip->bw_finish); +# ifdef CRYPT_NOT_INPLACE + } + else + { + char_u *outbuf; + + len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf, + ip->bw_finish); + if (len == 0) + return OK; // Crypt layer is buffering, will flush later. + wlen = write_eintr(ip->bw_fd, outbuf, len); + vim_free(outbuf); + return (wlen < len) ? FAIL : OK; + } +# endif + } +#endif + + wlen = write_eintr(ip->bw_fd, buf, len); + return (wlen < len) ? FAIL : OK; +} + +/* + * Check modification time of file, before writing to it. + * The size isn't checked, because using a tool like "gzip" takes care of + * using the same timestamp but can't set the size. + */ + static int +check_mtime(buf_T *buf, stat_T *st) +{ + if (buf->b_mtime_read != 0 + && time_differs(st, buf->b_mtime_read, buf->b_mtime_read_ns)) + { + msg_scroll = TRUE; // don't overwrite messages here + msg_silent = 0; // must give this prompt + // don't use emsg() here, don't want to flush the buffers + msg_attr(_("WARNING: The file has been changed since reading it!!!"), + HL_ATTR(HLF_E)); + if (ask_yesno((char_u *)_("Do you really want to write to it"), + TRUE) == 'n') + return FAIL; + msg_scroll = FALSE; // always overwrite the file message now + } + return OK; +} + +/* + * Generate a BOM in "buf[4]" for encoding "name". + * Return the length of the BOM (zero when no BOM). + */ + static int +make_bom(char_u *buf, char_u *name) +{ + int flags; + char_u *p; + + flags = get_fio_flags(name); + + // Can't put a BOM in a non-Unicode file. + if (flags == FIO_LATIN1 || flags == 0) + return 0; + + if (flags == FIO_UTF8) // UTF-8 + { + buf[0] = 0xef; + buf[1] = 0xbb; + buf[2] = 0xbf; + return 3; + } + p = buf; + (void)ucs2bytes(0xfeff, &p, flags); + return (int)(p - buf); +} + +#ifdef UNIX + static void +set_file_time( + char_u *fname, + time_t atime, // access time + time_t mtime) // modification time +{ +# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H) + struct utimbuf buf; + + buf.actime = atime; + buf.modtime = mtime; + (void)utime((char *)fname, &buf); +# else +# if defined(HAVE_UTIMES) + struct timeval tvp[2]; + + tvp[0].tv_sec = atime; + tvp[0].tv_usec = 0; + tvp[1].tv_sec = mtime; + tvp[1].tv_usec = 0; +# ifdef NeXT + (void)utimes((char *)fname, tvp); +# else + (void)utimes((char *)fname, (const struct timeval *)&tvp); +# endif +# endif +# endif +} +#endif // UNIX + + char * +new_file_message(void) +{ + return shortmess(SHM_NEW) ? _("[New]") : _("[New File]"); +} + +/* + * buf_write() - write to file "fname" lines "start" through "end" + * + * We do our own buffering here because fwrite() is so slow. + * + * If "forceit" is true, we don't care for errors when attempting backups. + * In case of an error everything possible is done to restore the original + * file. But when "forceit" is TRUE, we risk losing it. + * + * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and + * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed. + * + * This function must NOT use NameBuff (because it's called by autowrite()). + * + * return FAIL for failure, OK otherwise + */ + int +buf_write( + buf_T *buf, + char_u *fname, + char_u *sfname, + linenr_T start, + linenr_T end, + exarg_T *eap, // for forced 'ff' and 'fenc', can be + // NULL! + int append, // append to the file + int forceit, + int reset_changed, + int filtering) +{ + int fd; + char_u *backup = NULL; + int backup_copy = FALSE; // copy the original file? + int dobackup; + char_u *ffname; + char_u *wfname = NULL; // name of file to write to + char_u *s; + char_u *ptr; + char_u c; + int len; + linenr_T lnum; + long nchars; + char_u *errmsg = NULL; + int errmsg_allocated = FALSE; + char_u *errnum = NULL; + char_u *buffer; + char_u smallbuf[SMALLBUFSIZE]; + char_u *backup_ext; + int bufsize; + long perm; // file permissions + int retval = OK; + int newfile = FALSE; // TRUE if file doesn't exist yet + int msg_save = msg_scroll; + int overwriting; // TRUE if writing over original + int no_eol = FALSE; // no end-of-line written + int device = FALSE; // writing to a device + stat_T st_old; + int prev_got_int = got_int; + int checking_conversion; + int file_readonly = FALSE; // overwritten file is read-only +#if defined(UNIX) // XXX fix me sometime? + int made_writable = FALSE; // 'w' bit has been set +#endif + // writing everything + int whole = (start == 1 && end == buf->b_ml.ml_line_count); + linenr_T old_line_count = buf->b_ml.ml_line_count; + int attr; + int fileformat; + int write_bin; + struct bw_info write_info; // info for buf_write_bytes() + int converted = FALSE; + int notconverted = FALSE; + char_u *fenc; // effective 'fileencoding' + char_u *fenc_tofree = NULL; // allocated "fenc" + int wb_flags = 0; +#ifdef HAVE_ACL + vim_acl_T acl = NULL; // ACL copied from original file to + // backup or new file +#endif +#ifdef FEAT_PERSISTENT_UNDO + int write_undo_file = FALSE; + context_sha256_T sha_ctx; +#endif + unsigned int bkc = get_bkc_value(buf); + pos_T orig_start = buf->b_op_start; + pos_T orig_end = buf->b_op_end; + + if (fname == NULL || *fname == NUL) // safety check + return FAIL; + if (buf->b_ml.ml_mfp == NULL) + { + // This can happen during startup when there is a stray "w" in the + // vimrc file. + emsg(_(e_empty_buffer)); + return FAIL; + } + + // Disallow writing from .exrc and .vimrc in current directory for + // security reasons. + if (check_secure()) + return FAIL; + + // Avoid a crash for a long name. + if (STRLEN(fname) >= MAXPATHL) + { + emsg(_(e_name_too_long)); + return FAIL; + } + + // must init bw_conv_buf and bw_iconv_fd before jumping to "fail" + write_info.bw_conv_buf = NULL; + write_info.bw_conv_error = FALSE; + write_info.bw_conv_error_lnum = 0; + write_info.bw_restlen = 0; +#ifdef USE_ICONV + write_info.bw_iconv_fd = (iconv_t)-1; +#endif +#ifdef FEAT_CRYPT + write_info.bw_buffer = buf; + write_info.bw_finish = FALSE; +#endif + + // After writing a file changedtick changes but we don't want to display + // the line. + ex_no_reprint = TRUE; + + // If there is no file name yet, use the one for the written file. + // BF_NOTEDITED is set to reflect this (in case the write fails). + // Don't do this when the write is for a filter command. + // Don't do this when appending. + // Only do this when 'cpoptions' contains the 'F' flag. + if (buf->b_ffname == NULL + && reset_changed + && whole + && buf == curbuf + && !bt_nofilename(buf) + && !filtering + && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL) + && vim_strchr(p_cpo, CPO_FNAMEW) != NULL) + { + if (set_rw_fname(fname, sfname) == FAIL) + return FAIL; + buf = curbuf; // just in case autocmds made "buf" invalid + } + + if (sfname == NULL) + sfname = fname; + // For Unix: Use the short file name whenever possible. + // Avoids problems with networks and when directory names are changed. + // Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to + // another directory, which we don't detect + ffname = fname; // remember full fname +#ifdef UNIX + fname = sfname; +#endif + + if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0) + overwriting = TRUE; + else + overwriting = FALSE; + + if (exiting) + settmode(TMODE_COOK); // when exiting allow typeahead now + + ++no_wait_return; // don't wait for return yet + + // Set '[ and '] marks to the lines to be written. + buf->b_op_start.lnum = start; + buf->b_op_start.col = 0; + buf->b_op_end.lnum = end; + buf->b_op_end.col = 0; + + { + aco_save_T aco; + int buf_ffname = FALSE; + int buf_sfname = FALSE; + int buf_fname_f = FALSE; + int buf_fname_s = FALSE; + int did_cmd = FALSE; + int nofile_err = FALSE; + int empty_memline = (buf->b_ml.ml_mfp == NULL); + bufref_T bufref; + + // Apply PRE autocommands. + // Set curbuf to the buffer to be written. + // Careful: The autocommands may call buf_write() recursively! + if (ffname == buf->b_ffname) + buf_ffname = TRUE; + if (sfname == buf->b_sfname) + buf_sfname = TRUE; + if (fname == buf->b_ffname) + buf_fname_f = TRUE; + if (fname == buf->b_sfname) + buf_fname_s = TRUE; + + // Set curwin/curbuf to buf and save a few things. + aucmd_prepbuf(&aco, buf); + if (curbuf != buf) + { + // Could not find a window for "buf". Doing more might cause + // problems, better bail out. + return FAIL; + } + + set_bufref(&bufref, buf); + + if (append) + { + if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, + sfname, sfname, FALSE, curbuf, eap))) + { + if (overwriting && bt_nofilename(curbuf)) + nofile_err = TRUE; + else + apply_autocmds_exarg(EVENT_FILEAPPENDPRE, + sfname, sfname, FALSE, curbuf, eap); + } + } + else if (filtering) + { + apply_autocmds_exarg(EVENT_FILTERWRITEPRE, + NULL, sfname, FALSE, curbuf, eap); + } + else if (reset_changed && whole) + { + int was_changed = curbufIsChanged(); + + did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, + sfname, sfname, FALSE, curbuf, eap); + if (did_cmd) + { + if (was_changed && !curbufIsChanged()) + { + // Written everything correctly and BufWriteCmd has reset + // 'modified': Correct the undo information so that an + // undo now sets 'modified'. + u_unchanged(curbuf); + u_update_save_nr(curbuf); + } + } + else + { + if (overwriting && bt_nofilename(curbuf)) + nofile_err = TRUE; + else + apply_autocmds_exarg(EVENT_BUFWRITEPRE, + sfname, sfname, FALSE, curbuf, eap); + } + } + else + { + if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, + sfname, sfname, FALSE, curbuf, eap))) + { + if (overwriting && bt_nofilename(curbuf)) + nofile_err = TRUE; + else + apply_autocmds_exarg(EVENT_FILEWRITEPRE, + sfname, sfname, FALSE, curbuf, eap); + } + } + + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + + // In three situations we return here and don't write the file: + // 1. the autocommands deleted or unloaded the buffer. + // 2. The autocommands abort script processing. + // 3. If one of the "Cmd" autocommands was executed. + if (!bufref_valid(&bufref)) + buf = NULL; + if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline) + || did_cmd || nofile_err +#ifdef FEAT_EVAL + || aborting() +#endif + ) + { + if (buf != NULL && (cmdmod.cmod_flags & CMOD_LOCKMARKS)) + { + // restore the original '[ and '] positions + buf->b_op_start = orig_start; + buf->b_op_end = orig_end; + } + + --no_wait_return; + msg_scroll = msg_save; + if (nofile_err) + semsg(_(e_no_matching_autocommands_for_buftype_str_buffer), + curbuf->b_p_bt); + + if (nofile_err +#ifdef FEAT_EVAL + || aborting() +#endif + ) + // An aborting error, interrupt or exception in the + // autocommands. + return FAIL; + if (did_cmd) + { + if (buf == NULL) + // The buffer was deleted. We assume it was written + // (can't retry anyway). + return OK; + if (overwriting) + { + // Assume the buffer was written, update the timestamp. + ml_timestamp(buf); + if (append) + buf->b_flags &= ~BF_NEW; + else + buf->b_flags &= ~BF_WRITE_MASK; + } + if (reset_changed && buf->b_changed && !append + && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) + // Buffer still changed, the autocommands didn't work + // properly. + return FAIL; + return OK; + } +#ifdef FEAT_EVAL + if (!aborting()) +#endif + emsg(_(e_autocommands_deleted_or_unloaded_buffer_to_be_written)); + return FAIL; + } + + // The autocommands may have changed the number of lines in the file. + // When writing the whole file, adjust the end. + // When writing part of the file, assume that the autocommands only + // changed the number of lines that are to be written (tricky!). + if (buf->b_ml.ml_line_count != old_line_count) + { + if (whole) // write all + end = buf->b_ml.ml_line_count; + else if (buf->b_ml.ml_line_count > old_line_count) // more lines + end += buf->b_ml.ml_line_count - old_line_count; + else // less lines + { + end -= old_line_count - buf->b_ml.ml_line_count; + if (end < start) + { + --no_wait_return; + msg_scroll = msg_save; + emsg(_(e_autocommands_changed_number_of_lines_in_unexpected_way)); + return FAIL; + } + } + } + + // The autocommands may have changed the name of the buffer, which may + // be kept in fname, ffname and sfname. + if (buf_ffname) + ffname = buf->b_ffname; + if (buf_sfname) + sfname = buf->b_sfname; + if (buf_fname_f) + fname = buf->b_ffname; + if (buf_fname_s) + fname = buf->b_sfname; + } + + if (cmdmod.cmod_flags & CMOD_LOCKMARKS) + { + // restore the original '[ and '] positions + buf->b_op_start = orig_start; + buf->b_op_end = orig_end; + } + +#ifdef FEAT_NETBEANS_INTG + if (netbeans_active() && isNetbeansBuffer(buf)) + { + if (whole) + { + // b_changed can be 0 after an undo, but we still need to write + // the buffer to NetBeans. + if (buf->b_changed || isNetbeansModified(buf)) + { + --no_wait_return; // may wait for return now + msg_scroll = msg_save; + netbeans_save_buffer(buf); // no error checking... + return retval; + } + else + { + errnum = (char_u *)"E656: "; + errmsg = (char_u *)_(e_netbeans_disallows_writes_of_unmodified_buffers); + buffer = NULL; + goto fail; + } + } + else + { + errnum = (char_u *)"E657: "; + errmsg = (char_u *)_(e_partial_writes_disallowed_for_netbeans_buffers); + buffer = NULL; + goto fail; + } + } +#endif + + if (shortmess(SHM_OVER) && !exiting) + msg_scroll = FALSE; // overwrite previous file message + else + msg_scroll = TRUE; // don't overwrite previous file message + if (!filtering) + filemess(buf, +#ifndef UNIX + sfname, +#else + fname, +#endif + (char_u *)"", 0); // show that we are busy + msg_scroll = FALSE; // always overwrite the file message now + + buffer = alloc(WRITEBUFSIZE); + if (buffer == NULL) // can't allocate big buffer, use small + // one (to be able to write when out of + // memory) + { + buffer = smallbuf; + bufsize = SMALLBUFSIZE; + } + else + bufsize = WRITEBUFSIZE; + + // Get information about original file (if there is one). +#if defined(UNIX) + st_old.st_dev = 0; + st_old.st_ino = 0; + perm = -1; + if (mch_stat((char *)fname, &st_old) < 0) + newfile = TRUE; + else + { + perm = st_old.st_mode; + if (!S_ISREG(st_old.st_mode)) // not a file + { + if (S_ISDIR(st_old.st_mode)) + { + errnum = (char_u *)"E502: "; + errmsg = (char_u *)_(e_is_a_directory); + goto fail; + } + if (mch_nodetype(fname) != NODE_WRITABLE) + { + errnum = (char_u *)"E503: "; + errmsg = (char_u *)_(e_is_not_file_or_writable_device); + goto fail; + } + // It's a device of some kind (or a fifo) which we can write to + // but for which we can't make a backup. + device = TRUE; + newfile = TRUE; + perm = -1; + } + } +#else // !UNIX + // Check for a writable device name. + c = mch_nodetype(fname); + if (c == NODE_OTHER) + { + errnum = (char_u *)"E503: "; + errmsg = (char_u *)_(e_is_not_file_or_writable_device); + goto fail; + } + if (c == NODE_WRITABLE) + { +# if defined(MSWIN) + // MS-Windows allows opening a device, but we will probably get stuck + // trying to write to it. + if (!p_odev) + { + errnum = (char_u *)"E796: "; + errmsg = (char_u *)_(e_writing_to_device_disabled_with_opendevice_option); + goto fail; + } +# endif + device = TRUE; + newfile = TRUE; + perm = -1; + } + else + { + perm = mch_getperm(fname); + if (perm < 0) + newfile = TRUE; + else if (mch_isdir(fname)) + { + errnum = (char_u *)"E502: "; + errmsg = (char_u *)_(e_is_a_directory); + goto fail; + } + if (overwriting) + (void)mch_stat((char *)fname, &st_old); + } +#endif // !UNIX + + if (!device && !newfile) + { + // Check if the file is really writable (when renaming the file to + // make a backup we won't discover it later). + file_readonly = check_file_readonly(fname, (int)perm); + + if (!forceit && file_readonly) + { + if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) + { + errnum = (char_u *)"E504: "; + errmsg = (char_u *)_(e_is_read_only_cannot_override_W_in_cpoptions); + } + else + { + errnum = (char_u *)"E505: "; + errmsg = (char_u *)_(e_is_read_only_add_bang_to_override); + } + goto fail; + } + + // Check if the timestamp hasn't changed since reading the file. + if (overwriting) + { + retval = check_mtime(buf, &st_old); + if (retval == FAIL) + goto fail; + } + } + +#ifdef HAVE_ACL + // For systems that support ACL: get the ACL from the original file. + if (!newfile) + acl = mch_get_acl(fname); +#endif + + // If 'backupskip' is not empty, don't make a backup for some files. + dobackup = (p_wb || p_bk || *p_pm != NUL); + if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname)) + dobackup = FALSE; + + // Save the value of got_int and reset it. We don't want a previous + // interruption cancel writing, only hitting CTRL-C while writing should + // abort it. + prev_got_int = got_int; + got_int = FALSE; + + // Mark the buffer as 'being saved' to prevent changed buffer warnings + buf->b_saving = TRUE; + + // If we are not appending or filtering, the file exists, and the + // 'writebackup', 'backup' or 'patchmode' option is set, need a backup. + // When 'patchmode' is set also make a backup when appending. + // + // Do not make any backup, if 'writebackup' and 'backup' are both switched + // off. This helps when editing large files on almost-full disks. + if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) + { +#if defined(UNIX) || defined(MSWIN) + stat_T st; +#endif + + if ((bkc & BKC_YES) || append) // "yes" + backup_copy = TRUE; +#if defined(UNIX) || defined(MSWIN) + else if ((bkc & BKC_AUTO)) // "auto" + { + int i; + +# ifdef UNIX + // Don't rename the file when: + // - it's a hard link + // - it's a symbolic link + // - we don't have write permission in the directory + // - we can't set the owner/group of the new file + if (st_old.st_nlink > 1 + || mch_lstat((char *)fname, &st) < 0 + || st.st_dev != st_old.st_dev + || st.st_ino != st_old.st_ino +# ifndef HAVE_FCHOWN + || st.st_uid != st_old.st_uid + || st.st_gid != st_old.st_gid +# endif + ) + backup_copy = TRUE; + else +# else +# ifdef MSWIN + // On NTFS file systems hard links are possible. + if (mch_is_linked(fname)) + backup_copy = TRUE; + else +# endif +# endif + { + // Check if we can create a file and set the owner/group to + // the ones from the original file. + // First find a file name that doesn't exist yet (use some + // arbitrary numbers). + STRCPY(IObuff, fname); + fd = -1; + for (i = 4913; ; i += 123) + { + sprintf((char *)gettail(IObuff), "%d", i); + if (mch_lstat((char *)IObuff, &st) < 0) + { + fd = mch_open((char *)IObuff, + O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm); + if (fd < 0 && errno == EEXIST) + // If the same file name is created by another + // process between lstat() and open(), find another + // name. + continue; + break; + } + } + if (fd < 0) // can't write in directory + backup_copy = TRUE; + else + { +# ifdef UNIX +# ifdef HAVE_FCHOWN + vim_ignored = fchown(fd, st_old.st_uid, st_old.st_gid); +# endif + if (mch_stat((char *)IObuff, &st) < 0 + || st.st_uid != st_old.st_uid + || st.st_gid != st_old.st_gid + || (long)st.st_mode != perm) + backup_copy = TRUE; +# endif + // Close the file before removing it, on MS-Windows we + // can't delete an open file. + close(fd); + mch_remove(IObuff); +# ifdef MSWIN + // MS-Windows may trigger a virus scanner to open the + // file, we can't delete it then. Keep trying for half a + // second. + { + int try; + + for (try = 0; try < 10; ++try) + { + if (mch_lstat((char *)IObuff, &st) < 0) + break; + ui_delay(50L, TRUE); // wait 50 msec + mch_remove(IObuff); + } + } +# endif + } + } + } + + // Break symlinks and/or hardlinks if we've been asked to. + if ((bkc & BKC_BREAKSYMLINK) || (bkc & BKC_BREAKHARDLINK)) + { +# ifdef UNIX + int lstat_res; + + lstat_res = mch_lstat((char *)fname, &st); + + // Symlinks. + if ((bkc & BKC_BREAKSYMLINK) + && lstat_res == 0 + && st.st_ino != st_old.st_ino) + backup_copy = FALSE; + + // Hardlinks. + if ((bkc & BKC_BREAKHARDLINK) + && st_old.st_nlink > 1 + && (lstat_res != 0 || st.st_ino == st_old.st_ino)) + backup_copy = FALSE; +# else +# if defined(MSWIN) + // Symlinks. + if ((bkc & BKC_BREAKSYMLINK) && mch_is_symbolic_link(fname)) + backup_copy = FALSE; + + // Hardlinks. + if ((bkc & BKC_BREAKHARDLINK) && mch_is_hard_link(fname)) + backup_copy = FALSE; +# endif +# endif + } + +#endif + + // make sure we have a valid backup extension to use + if (*p_bex == NUL) + backup_ext = (char_u *)".bak"; + else + backup_ext = p_bex; + + if (backup_copy + && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0) + { + int bfd; + char_u *copybuf, *wp; + int some_error = FALSE; + stat_T st_new; + char_u *dirp; + char_u *rootname; +#if defined(UNIX) || defined(MSWIN) + char_u *p; +#endif +#if defined(UNIX) + int did_set_shortname; + mode_t umask_save; +#endif + + copybuf = alloc(WRITEBUFSIZE + 1); + if (copybuf == NULL) + { + some_error = TRUE; // out of memory + goto nobackup; + } + + // Try to make the backup in each directory in the 'bdir' option. + // + // Unix semantics has it, that we may have a writable file, + // that cannot be recreated with a simple open(..., O_CREAT, ) e.g: + // - the directory is not writable, + // - the file may be a symbolic link, + // - the file may belong to another user/group, etc. + // + // For these reasons, the existing writable file must be truncated + // and reused. Creation of a backup COPY will be attempted. + dirp = p_bdir; + while (*dirp) + { +#ifdef UNIX + st_new.st_ino = 0; + st_new.st_dev = 0; + st_new.st_gid = 0; +#endif + + // Isolate one directory name, using an entry in 'bdir'. + (void)copy_option_part(&dirp, copybuf, WRITEBUFSIZE, ","); + +#if defined(UNIX) || defined(MSWIN) + p = copybuf + STRLEN(copybuf); + if (after_pathsep(copybuf, p) && p[-1] == p[-2]) + // Ends with '//', use full path + if ((p = make_percent_swname(copybuf, fname)) != NULL) + { + backup = modname(p, backup_ext, FALSE); + vim_free(p); + } +#endif + rootname = get_file_in_dir(fname, copybuf); + if (rootname == NULL) + { + some_error = TRUE; // out of memory + goto nobackup; + } + +#if defined(UNIX) + did_set_shortname = FALSE; +#endif + + // May try twice if 'shortname' not set. + for (;;) + { + // Make the backup file name. + if (backup == NULL) + backup = buf_modname((buf->b_p_sn || buf->b_shortname), + rootname, backup_ext, FALSE); + if (backup == NULL) + { + vim_free(rootname); + some_error = TRUE; // out of memory + goto nobackup; + } + + // Check if backup file already exists. + if (mch_stat((char *)backup, &st_new) >= 0) + { +#ifdef UNIX + // Check if backup file is same as original file. + // May happen when modname() gave the same file back. + // E.g. silly link, or file name-length reached. + // If we don't check here, we either ruin the file + // when copying or erase it after writing. jw. + if (st_new.st_dev == st_old.st_dev + && st_new.st_ino == st_old.st_ino) + { + VIM_CLEAR(backup); // no backup file to delete + // may try again with 'shortname' set + if (!(buf->b_shortname || buf->b_p_sn)) + { + buf->b_shortname = TRUE; + did_set_shortname = TRUE; + continue; + } + // setting shortname didn't help + if (did_set_shortname) + buf->b_shortname = FALSE; + break; + } +#endif + + // If we are not going to keep the backup file, don't + // delete an existing one, try to use another name. + // Change one character, just before the extension. + if (!p_bk) + { + wp = backup + STRLEN(backup) - 1 + - STRLEN(backup_ext); + if (wp < backup) // empty file name ??? + wp = backup; + *wp = 'z'; + while (*wp > 'a' + && mch_stat((char *)backup, &st_new) >= 0) + --*wp; + // They all exist??? Must be something wrong. + if (*wp == 'a') + VIM_CLEAR(backup); + } + } + break; + } + vim_free(rootname); + + // Try to create the backup file + if (backup != NULL) + { + // remove old backup, if present + mch_remove(backup); + // Open with O_EXCL to avoid the file being created while + // we were sleeping (symlink hacker attack?). Reset umask + // if possible to avoid mch_setperm() below. +#ifdef UNIX + umask_save = umask(0); +#endif + bfd = mch_open((char *)backup, + O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW, + perm & 0777); +#ifdef UNIX + (void)umask(umask_save); +#endif + if (bfd < 0) + VIM_CLEAR(backup); + else + { + // Set file protection same as original file, but + // strip s-bit. Only needed if umask() wasn't used + // above. +#ifndef UNIX + (void)mch_setperm(backup, perm & 0777); +#else + // Try to set the group of the backup same as the + // original file. If this fails, set the protection + // bits for the group same as the protection bits for + // others. + if (st_new.st_gid != st_old.st_gid +# ifdef HAVE_FCHOWN // sequent-ptx lacks fchown() + && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0 +# endif + ) + mch_setperm(backup, + (perm & 0707) | ((perm & 07) << 3)); +# if defined(HAVE_SELINUX) || defined(HAVE_SMACK) + mch_copy_sec(fname, backup); +# endif +#endif + + // copy the file. + write_info.bw_fd = bfd; + write_info.bw_buf = copybuf; + write_info.bw_flags = FIO_NOCONVERT; + while ((write_info.bw_len = read_eintr(fd, copybuf, + WRITEBUFSIZE)) > 0) + { + if (buf_write_bytes(&write_info) == FAIL) + { + errmsg = (char_u *)_(e_cant_write_to_backup_file_add_bang_to_override); + break; + } + ui_breakcheck(); + if (got_int) + { + errmsg = (char_u *)_(e_interrupted); + break; + } + } + + if (close(bfd) < 0 && errmsg == NULL) + errmsg = (char_u *)_(e_close_error_for_backup_file_add_bang_to_write_anyway); + if (write_info.bw_len < 0) + errmsg = (char_u *)_(e_cant_read_file_for_backup_add_bang_to_write_anyway); +#ifdef UNIX + set_file_time(backup, st_old.st_atime, st_old.st_mtime); +#endif +#ifdef HAVE_ACL + mch_set_acl(backup, acl); +#endif +#if defined(HAVE_SELINUX) || defined(HAVE_SMACK) + mch_copy_sec(fname, backup); +#endif +#ifdef MSWIN + (void)mch_copy_file_attribute(fname, backup); +#endif + break; + } + } + } + nobackup: + close(fd); // ignore errors for closing read file + vim_free(copybuf); + + if (backup == NULL && errmsg == NULL) + errmsg = (char_u *)_(e_cannot_create_backup_file_add_bang_to_write_anyway); + // ignore errors when forceit is TRUE + if ((some_error || errmsg != NULL) && !forceit) + { + retval = FAIL; + goto fail; + } + errmsg = NULL; + } + else + { + char_u *dirp; + char_u *p; + char_u *rootname; + + // Make a backup by renaming the original file. + + // If 'cpoptions' includes the "W" flag, we don't want to + // overwrite a read-only file. But rename may be possible + // anyway, thus we need an extra check here. + if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) + { + errnum = (char_u *)"E504: "; + errmsg = (char_u *)_(e_is_read_only_cannot_override_W_in_cpoptions); + goto fail; + } + + // Form the backup file name - change path/fo.o.h to + // path/fo.o.h.bak Try all directories in 'backupdir', first one + // that works is used. + dirp = p_bdir; + while (*dirp) + { + // Isolate one directory name and make the backup file name. + (void)copy_option_part(&dirp, IObuff, IOSIZE, ","); + +#if defined(UNIX) || defined(MSWIN) + p = IObuff + STRLEN(IObuff); + if (after_pathsep(IObuff, p) && p[-1] == p[-2]) + // path ends with '//', use full path + if ((p = make_percent_swname(IObuff, fname)) != NULL) + { + backup = modname(p, backup_ext, FALSE); + vim_free(p); + } +#endif + if (backup == NULL) + { + rootname = get_file_in_dir(fname, IObuff); + if (rootname == NULL) + backup = NULL; + else + { + backup = buf_modname( + (buf->b_p_sn || buf->b_shortname), + rootname, backup_ext, FALSE); + vim_free(rootname); + } + } + + if (backup != NULL) + { + // If we are not going to keep the backup file, don't + // delete an existing one, try to use another name. + // Change one character, just before the extension. + if (!p_bk && mch_getperm(backup) >= 0) + { + p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext); + if (p < backup) // empty file name ??? + p = backup; + *p = 'z'; + while (*p > 'a' && mch_getperm(backup) >= 0) + --*p; + // They all exist??? Must be something wrong! + if (*p == 'a') + VIM_CLEAR(backup); + } + } + if (backup != NULL) + { + // Delete any existing backup and move the current version + // to the backup. For safety, we don't remove the backup + // until the write has finished successfully. And if the + // 'backup' option is set, leave it around. + + // If the renaming of the original file to the backup file + // works, quit here. + if (vim_rename(fname, backup) == 0) + break; + + VIM_CLEAR(backup); // don't do the rename below + } + } + if (backup == NULL && !forceit) + { + errmsg = (char_u *)_(e_cant_make_backup_file_add_bang_to_write_anyway); + goto fail; + } + } + } + +#if defined(UNIX) + // When using ":w!" and the file was read-only: make it writable + if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid() + && vim_strchr(p_cpo, CPO_FWRITE) == NULL) + { + perm |= 0200; + (void)mch_setperm(fname, perm); + made_writable = TRUE; + } +#endif + + // When using ":w!" and writing to the current file, 'readonly' makes no + // sense, reset it, unless 'Z' appears in 'cpoptions'. + if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL) + { + buf->b_p_ro = FALSE; + need_maketitle = TRUE; // set window title later + status_redraw_all(); // redraw status lines later + } + + if (end > buf->b_ml.ml_line_count) + end = buf->b_ml.ml_line_count; + if (buf->b_ml.ml_flags & ML_EMPTY) + start = end + 1; + + // If the original file is being overwritten, there is a small chance that + // we crash in the middle of writing. Therefore the file is preserved now. + // This makes all block numbers positive so that recovery does not need + // the original file. + // Don't do this if there is a backup file and we are exiting. + if (reset_changed && !newfile && overwriting + && !(exiting && backup != NULL)) + { + ml_preserve(buf, FALSE); + if (got_int) + { + errmsg = (char_u *)_(e_interrupted); + goto restore_backup; + } + } + +#ifdef VMS + vms_remove_version(fname); // remove version +#endif + // Default: write the file directly. May write to a temp file for + // multi-byte conversion. + wfname = fname; + + // Check for forced 'fileencoding' from "++opt=val" argument. + if (eap != NULL && eap->force_enc != 0) + { + fenc = eap->cmd + eap->force_enc; + fenc = enc_canonize(fenc); + fenc_tofree = fenc; + } + else + fenc = buf->b_p_fenc; + + // Check if the file needs to be converted. + converted = need_conversion(fenc); + + // Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or + // Latin1 to Unicode conversion. This is handled in buf_write_bytes(). + // Prepare the flags for it and allocate bw_conv_buf when needed. + if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0)) + { + wb_flags = get_fio_flags(fenc); + if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8)) + { + // Need to allocate a buffer to translate into. + if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8)) + write_info.bw_conv_buflen = bufsize * 2; + else // FIO_UCS4 + write_info.bw_conv_buflen = bufsize * 4; + write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen); + if (write_info.bw_conv_buf == NULL) + end = 0; + } + } + +#ifdef MSWIN + if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0) + { + // Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: + write_info.bw_conv_buflen = bufsize * 4; + write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen); + if (write_info.bw_conv_buf == NULL) + end = 0; + } +#endif + +#ifdef MACOS_CONVERT + if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0) + { + write_info.bw_conv_buflen = bufsize * 3; + write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen); + if (write_info.bw_conv_buf == NULL) + end = 0; + } +#endif + +#if defined(FEAT_EVAL) || defined(USE_ICONV) + if (converted && wb_flags == 0) + { +# ifdef USE_ICONV + // Use iconv() conversion when conversion is needed and it's not done + // internally. + write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc, + enc_utf8 ? (char_u *)"utf-8" : p_enc); + if (write_info.bw_iconv_fd != (iconv_t)-1) + { + // We're going to use iconv(), allocate a buffer to convert in. + write_info.bw_conv_buflen = bufsize * ICONV_MULT; + write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen); + if (write_info.bw_conv_buf == NULL) + end = 0; + write_info.bw_first = TRUE; + } +# ifdef FEAT_EVAL + else +# endif +# endif + +# ifdef FEAT_EVAL + // When the file needs to be converted with 'charconvert' after + // writing, write to a temp file instead and let the conversion + // overwrite the original file. + if (*p_ccv != NUL) + { + wfname = vim_tempname('w', FALSE); + if (wfname == NULL) // Can't write without a tempfile! + { + errmsg = (char_u *)_(e_cant_find_temp_file_for_writing); + goto restore_backup; + } + } +# endif + } +#endif + if (converted && wb_flags == 0 +#ifdef USE_ICONV + && write_info.bw_iconv_fd == (iconv_t)-1 +# endif +# ifdef FEAT_EVAL + && wfname == fname +# endif + ) + { + if (!forceit) + { + errmsg = (char_u *)_(e_cannot_convert_add_bang_to_write_without_conversion); + goto restore_backup; + } + notconverted = TRUE; + } + + // If conversion is taking place, we may first pretend to write and check + // for conversion errors. Then loop again to write for real. + // When not doing conversion this writes for real right away. + for (checking_conversion = TRUE; ; checking_conversion = FALSE) + { + // There is no need to check conversion when: + // - there is no conversion + // - we make a backup file, that can be restored in case of conversion + // failure. + if (!converted || dobackup) + checking_conversion = FALSE; + + if (checking_conversion) + { + // Make sure we don't write anything. + fd = -1; + write_info.bw_fd = fd; + } + else + { +#ifdef HAVE_FTRUNCATE +# define TRUNC_ON_OPEN 0 +#else +# define TRUNC_ON_OPEN O_TRUNC +#endif + // Open the file "wfname" for writing. + // We may try to open the file twice: If we can't write to the file + // and forceit is TRUE we delete the existing file and try to + // create a new one. If this still fails we may have lost the + // original file! (this may happen when the user reached his + // quotum for number of files). + // Appending will fail if the file does not exist and forceit is + // FALSE. + while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append + ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND) + : (O_CREAT | TRUNC_ON_OPEN)) + , perm < 0 ? 0666 : (perm & 0777))) < 0) + { + // A forced write will try to create a new file if the old one + // is still readonly. This may also happen when the directory + // is read-only. In that case the mch_remove() will fail. + if (errmsg == NULL) + { +#ifdef UNIX + stat_T st; + + // Don't delete the file when it's a hard or symbolic link. + if ((!newfile && st_old.st_nlink > 1) + || (mch_lstat((char *)fname, &st) == 0 + && (st.st_dev != st_old.st_dev + || st.st_ino != st_old.st_ino))) + errmsg = + (char_u *)_(e_cant_open_linked_file_for_writing); + else +#endif + { + errmsg = (char_u *)_(e_cant_open_file_for_writing); + if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL + && perm >= 0) + { +#ifdef UNIX + // we write to the file, thus it should be marked + // writable after all + if (!(perm & 0200)) + made_writable = TRUE; + perm |= 0200; + if (st_old.st_uid != getuid() + || st_old.st_gid != getgid()) + perm &= 0777; +#endif + if (!append) // don't remove when appending + mch_remove(wfname); + continue; + } + } + } + +restore_backup: + { + stat_T st; + + // If we failed to open the file, we don't need a backup. + // Throw it away. If we moved or removed the original file + // try to put the backup in its place. + if (backup != NULL && wfname == fname) + { + if (backup_copy) + { + // There is a small chance that we removed the + // original, try to move the copy in its place. + // This may not work if the vim_rename() fails. + // In that case we leave the copy around. + + // If file does not exist, put the copy in its + // place + if (mch_stat((char *)fname, &st) < 0) + vim_rename(backup, fname); + // if original file does exist throw away the copy + if (mch_stat((char *)fname, &st) >= 0) + mch_remove(backup); + } + else + { + // try to put the original file back + vim_rename(backup, fname); + } + } + + // if original file no longer exists give an extra warning + if (!newfile && mch_stat((char *)fname, &st) < 0) + end = 0; + } + + if (wfname != fname) + vim_free(wfname); + goto fail; + } + write_info.bw_fd = fd; + +#if defined(UNIX) + { + stat_T st; + + // Double check we are writing the intended file before making + // any changes. + if (overwriting + && (!dobackup || backup_copy) + && fname == wfname + && perm >= 0 + && mch_fstat(fd, &st) == 0 + && st.st_ino != st_old.st_ino) + { + close(fd); + errmsg = (char_u *)_(e_file_changed_while_writing); + goto fail; + } + } +#endif +#ifdef HAVE_FTRUNCATE + if (!append) + vim_ignored = ftruncate(fd, (off_t)0); +#endif + +#if defined(MSWIN) + if (backup != NULL && overwriting && !append) + (void)mch_copy_file_attribute(backup, wfname); + + if (!overwriting && !append) + { + if (buf->b_ffname != NULL) + (void)mch_copy_file_attribute(buf->b_ffname, wfname); + // Should copy resource fork + } +#endif + +#ifdef FEAT_CRYPT + if (*buf->b_p_key != NUL && !filtering) + { + char_u *header; + int header_len; + + buf->b_cryptstate = crypt_create_for_writing( + crypt_get_method_nr(buf), + buf->b_p_key, &header, &header_len); + if (buf->b_cryptstate == NULL || header == NULL) + end = 0; + else + { + // Write magic number, so that Vim knows how this file is + // encrypted when reading it back. + write_info.bw_buf = header; + write_info.bw_len = header_len; + write_info.bw_flags = FIO_NOCONVERT; + if (buf_write_bytes(&write_info) == FAIL) + end = 0; + wb_flags |= FIO_ENCRYPTED; + vim_free(header); + } + } +#endif + } + errmsg = NULL; + + write_info.bw_buf = buffer; + nchars = 0; + + // use "++bin", "++nobin" or 'binary' + if (eap != NULL && eap->force_bin != 0) + write_bin = (eap->force_bin == FORCE_BIN); + else + write_bin = buf->b_p_bin; + + // The BOM is written just after the encryption magic number. + // Skip it when appending and the file already existed, the BOM only + // makes sense at the start of the file. + if (buf->b_p_bomb && !write_bin && (!append || perm < 0)) + { + write_info.bw_len = make_bom(buffer, fenc); + if (write_info.bw_len > 0) + { + // don't convert, do encryption + write_info.bw_flags = FIO_NOCONVERT | wb_flags; + if (buf_write_bytes(&write_info) == FAIL) + end = 0; + else + nchars += write_info.bw_len; + } + } + write_info.bw_start_lnum = start; + +#ifdef FEAT_PERSISTENT_UNDO + write_undo_file = (buf->b_p_udf + && overwriting + && !append + && !filtering +# ifdef CRYPT_NOT_INPLACE + // writing undo file requires + // crypt_encode_inplace() + && (buf->b_cryptstate == NULL + || crypt_works_inplace(buf->b_cryptstate)) +# endif + && reset_changed + && !checking_conversion); +# ifdef CRYPT_NOT_INPLACE + // remove undo file if encrypting it is not possible + if (buf->b_p_udf + && overwriting + && !append + && !filtering + && !checking_conversion + && buf->b_cryptstate != NULL + && !crypt_works_inplace(buf->b_cryptstate)) + u_undofile_reset_and_delete(buf); +# endif + if (write_undo_file) + // Prepare for computing the hash value of the text. + sha256_start(&sha_ctx); +#endif + + write_info.bw_len = bufsize; + write_info.bw_flags = wb_flags; + fileformat = get_fileformat_force(buf, eap); + s = buffer; + len = 0; + for (lnum = start; lnum <= end; ++lnum) + { + // The next while loop is done once for each character written. + // Keep it fast! + ptr = ml_get_buf(buf, lnum, FALSE) - 1; +#ifdef FEAT_PERSISTENT_UNDO + if (write_undo_file) + sha256_update(&sha_ctx, ptr + 1, + (UINT32_T)(STRLEN(ptr + 1) + 1)); +#endif + while ((c = *++ptr) != NUL) + { + if (c == NL) + *s = NUL; // replace newlines with NULs + else if (c == CAR && fileformat == EOL_MAC) + *s = NL; // Mac: replace CRs with NLs + else + *s = c; + ++s; + if (++len != bufsize) + continue; +#ifdef FEAT_CRYPT + if (write_info.bw_fd > 0 && lnum == end + && (write_info.bw_flags & FIO_ENCRYPTED) + && *buf->b_p_key != NUL && !filtering + && *ptr == NUL) + write_info.bw_finish = TRUE; + #endif + if (buf_write_bytes(&write_info) == FAIL) + { + end = 0; // write error: break loop + break; + } + nchars += bufsize; + s = buffer; + len = 0; + write_info.bw_start_lnum = lnum; + } + // write failed or last line has no EOL: stop here + if (end == 0 + || (lnum == end + && (write_bin || !buf->b_p_fixeol) + && ((write_bin && lnum == buf->b_no_eol_lnum) + || (lnum == buf->b_ml.ml_line_count + && !buf->b_p_eol)))) + { + ++lnum; // written the line, count it + no_eol = TRUE; + break; + } + if (fileformat == EOL_UNIX) + *s++ = NL; + else + { + *s++ = CAR; // EOL_MAC or EOL_DOS: write CR + if (fileformat == EOL_DOS) // write CR-NL + { + if (++len == bufsize) + { + if (buf_write_bytes(&write_info) == FAIL) + { + end = 0; // write error: break loop + break; + } + nchars += bufsize; + s = buffer; + len = 0; + } + *s++ = NL; + } + } + if (++len == bufsize && end) + { + if (buf_write_bytes(&write_info) == FAIL) + { + end = 0; // write error: break loop + break; + } + nchars += bufsize; + s = buffer; + len = 0; + + ui_breakcheck(); + if (got_int) + { + end = 0; // Interrupted, break loop + break; + } + } +#ifdef VMS + // On VMS there is a problem: newlines get added when writing + // blocks at a time. Fix it by writing a line at a time. + // This is much slower! + // Explanation: VAX/DECC RTL insists that records in some RMS + // structures end with a newline (carriage return) character, and + // if they don't it adds one. + // With other RMS structures it works perfect without this fix. +# ifndef MIN +// Older DECC compiler for VAX doesn't define MIN() +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +# endif + if (buf->b_fab_rfm == FAB$C_VFC + || ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0)) + { + int b2write; + + buf->b_fab_mrs = (buf->b_fab_mrs == 0 + ? MIN(4096, bufsize) + : MIN(buf->b_fab_mrs, bufsize)); + + b2write = len; + while (b2write > 0) + { + write_info.bw_len = MIN(b2write, buf->b_fab_mrs); + if (buf_write_bytes(&write_info) == FAIL) + { + end = 0; + break; + } + b2write -= MIN(b2write, buf->b_fab_mrs); + } + write_info.bw_len = bufsize; + nchars += len; + s = buffer; + len = 0; + } +#endif + } + if (len > 0 && end > 0) + { + write_info.bw_len = len; +#ifdef FEAT_CRYPT + if (write_info.bw_fd > 0 && lnum >= end + && (write_info.bw_flags & FIO_ENCRYPTED) + && *buf->b_p_key != NUL && !filtering) + write_info.bw_finish = TRUE; + #endif + if (buf_write_bytes(&write_info) == FAIL) + end = 0; // write error + nchars += len; + } + + if (!buf->b_p_fixeol && buf->b_p_eof) + { + // write trailing CTRL-Z + (void)write_eintr(write_info.bw_fd, "\x1a", 1); + nchars++; + } + + // Stop when writing done or an error was encountered. + if (!checking_conversion || end == 0) + break; + + // If no error happened until now, writing should be ok, so loop to + // really write the buffer. + } + + // If we started writing, finish writing. Also when an error was + // encountered. + if (!checking_conversion) + { +#if defined(UNIX) && defined(HAVE_FSYNC) + // On many journaling file systems there is a bug that causes both the + // original and the backup file to be lost when halting the system + // right after writing the file. That's because only the meta-data is + // journalled. Syncing the file slows down the system, but assures it + // has been written to disk and we don't lose it. + // For a device do try the fsync() but don't complain if it does not + // work (could be a pipe). + // If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. + if (p_fs && vim_fsync(fd) != 0 && !device) + { + errmsg = (char_u *)_(e_fsync_failed); + end = 0; + } +#endif + +#if defined(HAVE_SELINUX) || defined(HAVE_SMACK) + // Probably need to set the security context. + if (!backup_copy) + mch_copy_sec(backup, wfname); +#endif + +#ifdef UNIX + // When creating a new file, set its owner/group to that of the + // original file. Get the new device and inode number. + if (backup != NULL && !backup_copy) + { +# ifdef HAVE_FCHOWN + stat_T st; + + // Don't change the owner when it's already OK, some systems remove + // permission or ACL stuff. + if (mch_stat((char *)wfname, &st) < 0 + || st.st_uid != st_old.st_uid + || st.st_gid != st_old.st_gid) + { + // changing owner might not be possible + vim_ignored = fchown(fd, st_old.st_uid, -1); + // if changing group fails clear the group permissions + if (fchown(fd, -1, st_old.st_gid) == -1 && perm > 0) + perm &= ~070; + } +# endif + buf_setino(buf); + } + else if (!buf->b_dev_valid) + // Set the inode when creating a new file. + buf_setino(buf); +#endif + +#ifdef UNIX + if (made_writable) + perm &= ~0200; // reset 'w' bit for security reasons +#endif +#ifdef HAVE_FCHMOD + // set permission of new file same as old file + if (perm >= 0) + (void)mch_fsetperm(fd, perm); +#endif + if (close(fd) != 0) + { + errmsg = (char_u *)_(e_close_failed); + end = 0; + } + +#ifndef HAVE_FCHMOD + // set permission of new file same as old file + if (perm >= 0) + (void)mch_setperm(wfname, perm); +#endif +#ifdef HAVE_ACL + // Probably need to set the ACL before changing the user (can't set the + // ACL on a file the user doesn't own). + // On Solaris, with ZFS and the aclmode property set to "discard" (the + // default), chmod() discards all part of a file's ACL that don't + // represent the mode of the file. It's non-trivial for us to discover + // whether we're in that situation, so we simply always re-set the ACL. +# ifndef HAVE_SOLARIS_ZFS_ACL + if (!backup_copy) +# endif + mch_set_acl(wfname, acl); +#endif +#ifdef FEAT_CRYPT + if (buf->b_cryptstate != NULL) + { + crypt_free_state(buf->b_cryptstate); + buf->b_cryptstate = NULL; + } +#endif + +#if defined(FEAT_EVAL) + if (wfname != fname) + { + // The file was written to a temp file, now it needs to be + // converted with 'charconvert' to (overwrite) the output file. + if (end != 0) + { + if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, + fenc, wfname, fname) == FAIL) + { + write_info.bw_conv_error = TRUE; + end = 0; + } + } + mch_remove(wfname); + vim_free(wfname); + } +#endif + } + + if (end == 0) + { + // Error encountered. + if (errmsg == NULL) + { + if (write_info.bw_conv_error) + { + if (write_info.bw_conv_error_lnum == 0) + errmsg = (char_u *)_(e_write_error_conversion_failed_make_fenc_empty_to_override); + else + { + errmsg_allocated = TRUE; + errmsg = alloc(300); + vim_snprintf((char *)errmsg, 300, _(e_write_error_conversion_failed_in_line_nr_make_fenc_empty_to_override), + (long)write_info.bw_conv_error_lnum); + } + } + else if (got_int) + errmsg = (char_u *)_(e_interrupted); + else + errmsg = (char_u *)_(e_write_error_file_system_full); + } + + // If we have a backup file, try to put it in place of the new file, + // because the new file is probably corrupt. This avoids losing the + // original file when trying to make a backup when writing the file a + // second time. + // When "backup_copy" is set we need to copy the backup over the new + // file. Otherwise rename the backup file. + // If this is OK, don't give the extra warning message. + if (backup != NULL) + { + if (backup_copy) + { + // This may take a while, if we were interrupted let the user + // know we got the message. + if (got_int) + { + msg(_(e_interrupted)); + out_flush(); + } + if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0) + { + if ((write_info.bw_fd = mch_open((char *)fname, + O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA, + perm & 0777)) >= 0) + { + // copy the file. + write_info.bw_buf = smallbuf; + write_info.bw_flags = FIO_NOCONVERT; + while ((write_info.bw_len = read_eintr(fd, smallbuf, + SMALLBUFSIZE)) > 0) + if (buf_write_bytes(&write_info) == FAIL) + break; + + if (close(write_info.bw_fd) >= 0 + && write_info.bw_len == 0) + end = 1; // success + } + close(fd); // ignore errors for closing read file + } + } + else + { + if (vim_rename(backup, fname) == 0) + end = 1; + } + } + goto fail; + } + + lnum -= start; // compute number of written lines + --no_wait_return; // may wait for return now + +#if !(defined(UNIX) || defined(VMS)) + fname = sfname; // use shortname now, for the messages +#endif + if (!filtering) + { + msg_add_fname(buf, fname); // put fname in IObuff with quotes + c = FALSE; + if (write_info.bw_conv_error) + { + STRCAT(IObuff, _(" CONVERSION ERROR")); + c = TRUE; + if (write_info.bw_conv_error_lnum != 0) + vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %ld;"), + (long)write_info.bw_conv_error_lnum); + } + else if (notconverted) + { + STRCAT(IObuff, _("[NOT converted]")); + c = TRUE; + } + else if (converted) + { + STRCAT(IObuff, _("[converted]")); + c = TRUE; + } + if (device) + { + STRCAT(IObuff, _("[Device]")); + c = TRUE; + } + else if (newfile) + { + STRCAT(IObuff, new_file_message()); + c = TRUE; + } + if (no_eol) + { + msg_add_eol(); + c = TRUE; + } + // may add [unix/dos/mac] + if (msg_add_fileformat(fileformat)) + c = TRUE; +#ifdef FEAT_CRYPT + if (wb_flags & FIO_ENCRYPTED) + { + crypt_append_msg(buf); + c = TRUE; + } +#endif + msg_add_lines(c, (long)lnum, nchars); // add line/char count + if (!shortmess(SHM_WRITE)) + { + if (append) + STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended")); + else + STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written")); + } + + set_keep_msg((char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0), 0); + } + + // When written everything correctly: reset 'modified'. Unless not + // writing to the original file and '+' is not in 'cpoptions'. + if (reset_changed && whole && !append + && !write_info.bw_conv_error + && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) + { + unchanged(buf, TRUE, FALSE); + // b:changedtick may be incremented in unchanged() but that should not + // trigger a TextChanged event. + if (buf->b_last_changedtick + 1 == CHANGEDTICK(buf)) + buf->b_last_changedtick = CHANGEDTICK(buf); + u_unchanged(buf); + u_update_save_nr(buf); + } + + // If written to the current file, update the timestamp of the swap file + // and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime. + if (overwriting) + { + ml_timestamp(buf); + if (append) + buf->b_flags &= ~BF_NEW; + else + buf->b_flags &= ~BF_WRITE_MASK; + } + + // If we kept a backup until now, and we are in patch mode, then we make + // the backup file our 'original' file. + if (*p_pm && dobackup) + { + char *org = (char *)buf_modname((buf->b_p_sn || buf->b_shortname), + fname, p_pm, FALSE); + + if (backup != NULL) + { + stat_T st; + + // If the original file does not exist yet + // the current backup file becomes the original file + if (org == NULL) + emsg(_(e_patchmode_cant_save_original_file)); + else if (mch_stat(org, &st) < 0) + { + vim_rename(backup, (char_u *)org); + VIM_CLEAR(backup); // don't delete the file +#ifdef UNIX + set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime); +#endif + } + } + // If there is no backup file, remember that a (new) file was + // created. + else + { + int empty_fd; + + if (org == NULL + || (empty_fd = mch_open(org, + O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW, + perm < 0 ? 0666 : (perm & 0777))) < 0) + emsg(_(e_patchmode_cant_touch_empty_original_file)); + else + close(empty_fd); + } + if (org != NULL) + { + mch_setperm((char_u *)org, mch_getperm(fname) & 0777); + vim_free(org); + } + } + + // Remove the backup unless 'backup' option is set or there was a + // conversion error. + if (!p_bk && backup != NULL && !write_info.bw_conv_error + && mch_remove(backup) != 0) + emsg(_(e_cant_delete_backup_file)); + + goto nofail; + + // Finish up. We get here either after failure or success. +fail: + --no_wait_return; // may wait for return now +nofail: + + // Done saving, we accept changed buffer warnings again + buf->b_saving = FALSE; + + vim_free(backup); + if (buffer != smallbuf) + vim_free(buffer); + vim_free(fenc_tofree); + vim_free(write_info.bw_conv_buf); +#ifdef USE_ICONV + if (write_info.bw_iconv_fd != (iconv_t)-1) + { + iconv_close(write_info.bw_iconv_fd); + write_info.bw_iconv_fd = (iconv_t)-1; + } +#endif +#ifdef HAVE_ACL + mch_free_acl(acl); +#endif + + if (errmsg != NULL) + { + int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0; + + attr = HL_ATTR(HLF_E); // set highlight for error messages + msg_add_fname(buf, +#ifndef UNIX + sfname +#else + fname +#endif + ); // put file name in IObuff with quotes + if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE) + IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL; + // If the error message has the form "is ...", put the error number in + // front of the file name. + if (errnum != NULL) + { + STRMOVE(IObuff + numlen, IObuff); + mch_memmove(IObuff, errnum, (size_t)numlen); + } + STRCAT(IObuff, errmsg); + emsg((char *)IObuff); + if (errmsg_allocated) + vim_free(errmsg); + + retval = FAIL; + if (end == 0) + { + msg_puts_attr(_("\nWARNING: Original file may be lost or damaged\n"), + attr | MSG_HIST); + msg_puts_attr(_("don't quit the editor until the file is successfully written!"), + attr | MSG_HIST); + + // Update the timestamp to avoid an "overwrite changed file" + // prompt when writing again. + if (mch_stat((char *)fname, &st_old) >= 0) + { + buf_store_time(buf, &st_old, fname); + buf->b_mtime_read = buf->b_mtime; + buf->b_mtime_read_ns = buf->b_mtime_ns; + } + } + } + msg_scroll = msg_save; + +#ifdef FEAT_PERSISTENT_UNDO + // When writing the whole file and 'undofile' is set, also write the undo + // file. + if (retval == OK && write_undo_file) + { + char_u hash[UNDO_HASH_SIZE]; + + sha256_finish(&sha_ctx, hash); + u_write_undo(NULL, FALSE, buf, hash); + } +#endif + +#ifdef FEAT_EVAL + if (!should_abort(retval)) +#else + if (!got_int) +#endif + { + aco_save_T aco; + + curbuf->b_no_eol_lnum = 0; // in case it was set by the previous read + + // Apply POST autocommands. + // Careful: The autocommands may call buf_write() recursively! + // Only do this when a window was found for "buf". + aucmd_prepbuf(&aco, buf); + if (curbuf == buf) + { + if (append) + apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname, + FALSE, curbuf, eap); + else if (filtering) + apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname, + FALSE, curbuf, eap); + else if (reset_changed && whole) + apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname, + FALSE, curbuf, eap); + else + apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname, + FALSE, curbuf, eap); + + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + } + +#ifdef FEAT_EVAL + if (aborting()) // autocmds may abort script processing + retval = FALSE; +#endif + } + +#ifdef FEAT_VIMINFO + // Make sure marks will be written out to the viminfo file later, even when + // the file is new. + curbuf->b_marks_read = TRUE; +#endif + + got_int |= prev_got_int; + + return retval; +} diff --git a/src/change.c b/src/change.c new file mode 100644 index 0000000..e5798c5 --- /dev/null +++ b/src/change.c @@ -0,0 +1,2392 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * change.c: functions related to changing text + */ + +#include "vim.h" + +/* + * If the file is readonly, give a warning message with the first change. + * Don't do this for autocommands. + * Doesn't use emsg(), because it flushes the macro buffer. + * If we have undone all changes b_changed will be FALSE, but "b_did_warn" + * will be TRUE. + * "col" is the column for the message; non-zero when in insert mode and + * 'showmode' is on. + * Careful: may trigger autocommands that reload the buffer. + */ + void +change_warning(int col) +{ + static char *w_readonly = N_("W10: Warning: Changing a readonly file"); + + if (curbuf->b_did_warn + || curbufIsChanged() + || autocmd_busy + || !curbuf->b_p_ro) + return; + + ++curbuf_lock; + apply_autocmds(EVENT_FILECHANGEDRO, NULL, NULL, FALSE, curbuf); + --curbuf_lock; + if (!curbuf->b_p_ro) + return; + + // Do what msg() does, but with a column offset if the warning should + // be after the mode message. + msg_start(); + if (msg_row == Rows - 1) + msg_col = col; + msg_source(HL_ATTR(HLF_W)); + msg_puts_attr(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST); +#ifdef FEAT_EVAL + set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_readonly), -1); +#endif + msg_clr_eos(); + (void)msg_end(); + if (msg_silent == 0 && !silent_mode +#ifdef FEAT_EVAL + && time_for_testing != 1 +#endif + ) + { + out_flush(); + ui_delay(1002L, TRUE); // give the user time to think about it + } + curbuf->b_did_warn = TRUE; + redraw_cmdline = FALSE; // don't redraw and erase the message + if (msg_row < Rows - 1) + showmode(); +} + +/* + * Call this function when something in the current buffer is changed. + * + * Most often called through changed_bytes() and changed_lines(), which also + * mark the area of the display to be redrawn. + * + * Careful: may trigger autocommands that reload the buffer. + */ + void +changed(void) +{ +#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) + if (p_imst == IM_ON_THE_SPOT) + { + // The text of the preediting area is inserted, but this doesn't + // mean a change of the buffer yet. That is delayed until the + // text is committed. (this means preedit becomes empty) + if (im_is_preediting() && !xim_changed_while_preediting) + return; + xim_changed_while_preediting = FALSE; + } +#endif + + if (!curbuf->b_changed) + { + int save_msg_scroll = msg_scroll; + + // Give a warning about changing a read-only file. This may also + // check-out the file, thus change "curbuf"! + change_warning(0); + + // Create a swap file if that is wanted. + // Don't do this for "nofile" and "nowrite" buffer types. + if (curbuf->b_may_swap && !bt_dontwrite(curbuf)) + { + int save_need_wait_return = need_wait_return; + + need_wait_return = FALSE; + ml_open_file(curbuf); + + // The ml_open_file() can cause an ATTENTION message. + // Wait two seconds, to make sure the user reads this unexpected + // message. Since we could be anywhere, call wait_return() now, + // and don't let the emsg() set msg_scroll. + if (need_wait_return && emsg_silent == 0 && !in_assert_fails) + { + out_flush(); + ui_delay(2002L, TRUE); + wait_return(TRUE); + msg_scroll = save_msg_scroll; + } + else + need_wait_return = save_need_wait_return; + } + changed_internal(); + } + ++CHANGEDTICK(curbuf); + +#ifdef FEAT_SEARCH_EXTRA + // If a pattern is highlighted, the position may now be invalid. + highlight_match = FALSE; +#endif +} + +/* + * Internal part of changed(), no user interaction. + * Also used for recovery. + */ + void +changed_internal(void) +{ + curbuf->b_changed = TRUE; + ml_setflags(curbuf); + check_status(curbuf); + redraw_tabline = TRUE; + need_maketitle = TRUE; // set window title later +} + +#ifdef FEAT_EVAL +static long next_listener_id = 0; + +/* + * Check if the change at "lnum" is above or overlaps with an existing + * change. If above then flush changes and invoke listeners. + */ + static void +check_recorded_changes( + buf_T *buf, + linenr_T lnum, + linenr_T lnume, + long xtra) +{ + if (buf->b_recorded_changes == NULL || xtra == 0) + return; + + listitem_T *li; + linenr_T prev_lnum; + linenr_T prev_lnume; + + FOR_ALL_LIST_ITEMS(buf->b_recorded_changes, li) + { + prev_lnum = (linenr_T)dict_get_number( + li->li_tv.vval.v_dict, "lnum"); + prev_lnume = (linenr_T)dict_get_number( + li->li_tv.vval.v_dict, "end"); + if (prev_lnum >= lnum || prev_lnum > lnume || prev_lnume >= lnum) + { + // the current change is going to make the line number in + // the older change invalid, flush now + invoke_listeners(curbuf); + break; + } + } +} + +/* + * Record a change for listeners added with listener_add(). + * Always for the current buffer. + */ + static void +may_record_change( + linenr_T lnum, + colnr_T col, + linenr_T lnume, + long xtra) +{ + dict_T *dict; + + if (curbuf->b_listener == NULL) + return; + + // If the new change is going to change the line numbers in already listed + // changes, then flush. + check_recorded_changes(curbuf, lnum, lnume, xtra); + + if (curbuf->b_recorded_changes == NULL) + { + curbuf->b_recorded_changes = list_alloc(); + if (curbuf->b_recorded_changes == NULL) // out of memory + return; + ++curbuf->b_recorded_changes->lv_refcount; + curbuf->b_recorded_changes->lv_lock = VAR_FIXED; + } + + dict = dict_alloc(); + if (dict == NULL) + return; + dict_add_number(dict, "lnum", (varnumber_T)lnum); + dict_add_number(dict, "end", (varnumber_T)lnume); + dict_add_number(dict, "added", (varnumber_T)xtra); + dict_add_number(dict, "col", (varnumber_T)col + 1); + + list_append_dict(curbuf->b_recorded_changes, dict); +} + +/* + * listener_add() function + */ + void +f_listener_add(typval_T *argvars, typval_T *rettv) +{ + callback_T callback; + listener_T *lnr; + buf_T *buf = curbuf; + + if (in_vim9script() && check_for_opt_buffer_arg(argvars, 1) == FAIL) + return; + + callback = get_callback(&argvars[0]); + if (callback.cb_name == NULL) + return; + + if (argvars[1].v_type != VAR_UNKNOWN) + { + buf = get_buf_arg(&argvars[1]); + if (buf == NULL) + { + free_callback(&callback); + return; + } + } + + lnr = ALLOC_CLEAR_ONE(listener_T); + if (lnr == NULL) + { + free_callback(&callback); + return; + } + lnr->lr_next = buf->b_listener; + buf->b_listener = lnr; + + set_callback(&lnr->lr_callback, &callback); + if (callback.cb_free_name) + vim_free(callback.cb_name); + + lnr->lr_id = ++next_listener_id; + rettv->vval.v_number = lnr->lr_id; +} + +/* + * listener_flush() function + */ + void +f_listener_flush(typval_T *argvars, typval_T *rettv UNUSED) +{ + buf_T *buf = curbuf; + + if (in_vim9script() && check_for_opt_buffer_arg(argvars, 0) == FAIL) + return; + + if (argvars[0].v_type != VAR_UNKNOWN) + { + buf = get_buf_arg(&argvars[0]); + if (buf == NULL) + return; + } + invoke_listeners(buf); +} + + + static void +remove_listener(buf_T *buf, listener_T *lnr, listener_T *prev) +{ + if (prev != NULL) + prev->lr_next = lnr->lr_next; + else + buf->b_listener = lnr->lr_next; + free_callback(&lnr->lr_callback); + vim_free(lnr); +} + +/* + * listener_remove() function + */ + void +f_listener_remove(typval_T *argvars, typval_T *rettv) +{ + listener_T *lnr; + listener_T *next; + listener_T *prev; + int id; + buf_T *buf; + + if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) + return; + + id = tv_get_number(argvars); + FOR_ALL_BUFFERS(buf) + { + prev = NULL; + for (lnr = buf->b_listener; lnr != NULL; lnr = next) + { + next = lnr->lr_next; + if (lnr->lr_id == id) + { + if (textlock > 0) + { + // in invoke_listeners(), clear ID and delete later + lnr->lr_id = 0; + return; + } + remove_listener(buf, lnr, prev); + rettv->vval.v_number = 1; + return; + } + prev = lnr; + } + } +} + +/* + * Called before inserting a line above "lnum"/"lnum3" or deleting line "lnum" + * to "lnume". + */ + void +may_invoke_listeners(buf_T *buf, linenr_T lnum, linenr_T lnume, int added) +{ + check_recorded_changes(buf, lnum, lnume, added); +} + +/* + * Called when a sequence of changes is done: invoke listeners added with + * listener_add(). + */ + void +invoke_listeners(buf_T *buf) +{ + listener_T *lnr; + typval_T rettv; + typval_T argv[6]; + listitem_T *li; + linenr_T start = MAXLNUM; + linenr_T end = 0; + linenr_T added = 0; + int save_updating_screen = updating_screen; + static int recursive = FALSE; + listener_T *next; + listener_T *prev; + + if (buf->b_recorded_changes == NULL // nothing changed + || buf->b_listener == NULL // no listeners + || recursive) // already busy + return; + recursive = TRUE; + + // Block messages on channels from being handled, so that they don't make + // text changes here. + ++updating_screen; + + argv[0].v_type = VAR_NUMBER; + argv[0].vval.v_number = buf->b_fnum; // a:bufnr + + FOR_ALL_LIST_ITEMS(buf->b_recorded_changes, li) + { + varnumber_T lnum; + + lnum = dict_get_number(li->li_tv.vval.v_dict, "lnum"); + if (start > lnum) + start = lnum; + lnum = dict_get_number(li->li_tv.vval.v_dict, "end"); + if (end < lnum) + end = lnum; + added += dict_get_number(li->li_tv.vval.v_dict, "added"); + } + argv[1].v_type = VAR_NUMBER; + argv[1].vval.v_number = start; + argv[2].v_type = VAR_NUMBER; + argv[2].vval.v_number = end; + argv[3].v_type = VAR_NUMBER; + argv[3].vval.v_number = added; + + argv[4].v_type = VAR_LIST; + argv[4].vval.v_list = buf->b_recorded_changes; + ++textlock; + + for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next) + { + call_callback(&lnr->lr_callback, -1, &rettv, 5, argv); + clear_tv(&rettv); + } + + // If f_listener_remove() was called may have to remove a listener now. + prev = NULL; + for (lnr = buf->b_listener; lnr != NULL; lnr = next) + { + next = lnr->lr_next; + if (lnr->lr_id == 0) + remove_listener(buf, lnr, prev); + else + prev = lnr; + } + + --textlock; + list_unref(buf->b_recorded_changes); + buf->b_recorded_changes = NULL; + + if (save_updating_screen) + updating_screen = TRUE; + else + after_updating_screen(TRUE); + recursive = FALSE; +} + +/* + * Remove all listeners associated with "buf". + */ + void +remove_listeners(buf_T *buf) +{ + listener_T *lnr; + listener_T *next; + + for (lnr = buf->b_listener; lnr != NULL; lnr = next) + { + next = lnr->lr_next; + free_callback(&lnr->lr_callback); + vim_free(lnr); + } + buf->b_listener = NULL; +} +#endif + +/* + * Common code for when a change was made. + * See changed_lines() for the arguments. + * Careful: may trigger autocommands that reload the buffer. + */ + static void +changed_common( + linenr_T lnum, + colnr_T col, + linenr_T lnume, + long xtra) +{ + win_T *wp; + tabpage_T *tp; + int i; + int cols; + pos_T *p; + int add; + + // mark the buffer as modified + changed(); + +#ifdef FEAT_EVAL + may_record_change(lnum, col, lnume, xtra); +#endif +#ifdef FEAT_DIFF + if (curwin->w_p_diff && diff_internal()) + curtab->tp_diff_update = TRUE; +#endif + + // set the '. mark + if ((cmdmod.cmod_flags & CMOD_KEEPJUMPS) == 0) + { + curbuf->b_last_change.lnum = lnum; + curbuf->b_last_change.col = col; + + // Create a new entry if a new undo-able change was started or we + // don't have an entry yet. + if (curbuf->b_new_change || curbuf->b_changelistlen == 0) + { + if (curbuf->b_changelistlen == 0) + add = TRUE; + else + { + // Don't create a new entry when the line number is the same + // as the last one and the column is not too far away. Avoids + // creating many entries for typing "xxxxx". + p = &curbuf->b_changelist[curbuf->b_changelistlen - 1]; + if (p->lnum != lnum) + add = TRUE; + else + { + cols = comp_textwidth(FALSE); + if (cols == 0) + cols = 79; + add = (p->col + cols < col || col + cols < p->col); + } + } + if (add) + { + // This is the first of a new sequence of undo-able changes + // and it's at some distance of the last change. Use a new + // position in the changelist. + curbuf->b_new_change = FALSE; + + if (curbuf->b_changelistlen == JUMPLISTSIZE) + { + // changelist is full: remove oldest entry + curbuf->b_changelistlen = JUMPLISTSIZE - 1; + mch_memmove(curbuf->b_changelist, curbuf->b_changelist + 1, + sizeof(pos_T) * (JUMPLISTSIZE - 1)); + FOR_ALL_TAB_WINDOWS(tp, wp) + { + // Correct position in changelist for other windows on + // this buffer. + if (wp->w_buffer == curbuf && wp->w_changelistidx > 0) + --wp->w_changelistidx; + } + } + FOR_ALL_TAB_WINDOWS(tp, wp) + { + // For other windows, if the position in the changelist is + // at the end it stays at the end. + if (wp->w_buffer == curbuf + && wp->w_changelistidx == curbuf->b_changelistlen) + ++wp->w_changelistidx; + } + ++curbuf->b_changelistlen; + } + } + curbuf->b_changelist[curbuf->b_changelistlen - 1] = + curbuf->b_last_change; + // The current window is always after the last change, so that "g," + // takes you back to it. + curwin->w_changelistidx = curbuf->b_changelistlen; + } + + if (VIsual_active) + check_visual_pos(); + + FOR_ALL_TAB_WINDOWS(tp, wp) + { + if (wp->w_buffer == curbuf) + { +#ifdef FEAT_FOLDING + linenr_T last = lnume + xtra - 1; // last line after the change +#endif + // Mark this window to be redrawn later. + if (!redraw_not_allowed && wp->w_redr_type < UPD_VALID) + wp->w_redr_type = UPD_VALID; + + // Check if a change in the buffer has invalidated the cached + // values for the cursor. +#ifdef FEAT_FOLDING + // Update the folds for this window. Can't postpone this, because + // a following operator might work on the whole fold: ">>dd". + foldUpdate(wp, lnum, last); + + // The change may cause lines above or below the change to become + // included in a fold. Set lnum/lnume to the first/last line that + // might be displayed differently. + // Set w_cline_folded here as an efficient way to update it when + // inserting lines just above a closed fold. + i = hasFoldingWin(wp, lnum, &lnum, NULL, FALSE, NULL); + if (wp->w_cursor.lnum == lnum) + wp->w_cline_folded = i; + i = hasFoldingWin(wp, last, NULL, &last, FALSE, NULL); + if (wp->w_cursor.lnum == last) + wp->w_cline_folded = i; + + // If the changed line is in a range of previously folded lines, + // compare with the first line in that range. + if (wp->w_cursor.lnum <= lnum) + { + i = find_wl_entry(wp, lnum); + if (i >= 0 && wp->w_cursor.lnum > wp->w_lines[i].wl_lnum) + changed_line_abv_curs_win(wp); + } +#endif + if (wp->w_cursor.lnum > lnum) + changed_line_abv_curs_win(wp); + else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col) + changed_cline_bef_curs_win(wp); + if (wp->w_botline >= lnum) + { + if (xtra < 0) + invalidate_botline_win(wp); + else + // Assume that botline doesn't change (inserted lines make + // other lines scroll down below botline). + approximate_botline_win(wp); + } + + // Check if any w_lines[] entries have become invalid. + // For entries below the change: Correct the lnums for + // inserted/deleted lines. Makes it possible to stop displaying + // after the change. + for (i = 0; i < wp->w_lines_valid; ++i) + if (wp->w_lines[i].wl_valid) + { + if (wp->w_lines[i].wl_lnum >= lnum) + { + // Do not change wl_lnum at index zero, it is used to + // compare with w_topline. Invalidate it instead. + if (wp->w_lines[i].wl_lnum < lnume || i == 0) + { + // line included in change + wp->w_lines[i].wl_valid = FALSE; + } + else if (xtra != 0) + { + // line below change + wp->w_lines[i].wl_lnum += xtra; +#ifdef FEAT_FOLDING + wp->w_lines[i].wl_lastlnum += xtra; +#endif + } + } +#ifdef FEAT_FOLDING + else if (wp->w_lines[i].wl_lastlnum >= lnum) + { + // change somewhere inside this range of folded lines, + // may need to be redrawn + wp->w_lines[i].wl_valid = FALSE; + } +#endif + } + +#ifdef FEAT_FOLDING + // Take care of side effects for setting w_topline when folds have + // changed. Esp. when the buffer was changed in another window. + if (hasAnyFolding(wp)) + set_topline(wp, wp->w_topline); +#endif + // If lines have been added or removed, relative numbering always + // requires a redraw. + if (wp->w_p_rnu && xtra != 0) + { + wp->w_last_cursor_lnum_rnu = 0; + redraw_win_later(wp, UPD_VALID); + } +#ifdef FEAT_SYN_HL + // Cursor line highlighting probably need to be updated with + // "UPD_VALID" if it's below the change. + // If the cursor line is inside the change we need to redraw more. + if (wp->w_p_cul) + { + if (xtra == 0) + redraw_win_later(wp, UPD_VALID); + else if (lnum <= wp->w_last_cursorline) + redraw_win_later(wp, UPD_SOME_VALID); + } +#endif + } +#ifdef FEAT_SEARCH_EXTRA + if (wp == curwin && xtra != 0 && search_hl_has_cursor_lnum >= lnum) + search_hl_has_cursor_lnum += xtra; +#endif + } + + // Call update_screen() later, which checks out what needs to be redrawn, + // since it notices b_mod_set and then uses b_mod_*. + set_must_redraw(UPD_VALID); + + // when the cursor line is changed always trigger CursorMoved + if (lnum <= curwin->w_cursor.lnum + && lnume + (xtra < 0 ? -xtra : xtra) > curwin->w_cursor.lnum) + last_cursormoved.lnum = 0; +} + + static void +changedOneline(buf_T *buf, linenr_T lnum) +{ + if (buf->b_mod_set) + { + // find the maximum area that must be redisplayed + if (lnum < buf->b_mod_top) + buf->b_mod_top = lnum; + else if (lnum >= buf->b_mod_bot) + buf->b_mod_bot = lnum + 1; + } + else + { + // set the area that must be redisplayed to one line + buf->b_mod_set = TRUE; + buf->b_mod_top = lnum; + buf->b_mod_bot = lnum + 1; + buf->b_mod_xlines = 0; + } +} + +/* + * Changed bytes within a single line for the current buffer. + * - marks the windows on this buffer to be redisplayed + * - marks the buffer changed by calling changed() + * - invalidates cached values + * Careful: may trigger autocommands that reload the buffer. + */ + void +changed_bytes(linenr_T lnum, colnr_T col) +{ + changedOneline(curbuf, lnum); + changed_common(lnum, col, lnum + 1, 0L); + +#ifdef FEAT_SPELL + // When text has been changed at the end of the line, possibly the start of + // the next line may have SpellCap that should be removed or it needs to be + // displayed. Schedule the next line for redrawing just in case. + // Don't do this when displaying '$' at the end of changed text. + if (spell_check_window(curwin) + && lnum < curbuf->b_ml.ml_line_count + && vim_strchr(p_cpo, CPO_DOLLAR) == NULL) + redrawWinline(curwin, lnum + 1); +#endif +#ifdef FEAT_DIFF + // Diff highlighting in other diff windows may need to be updated too. + if (curwin->w_p_diff) + { + win_T *wp; + linenr_T wlnum; + + FOR_ALL_WINDOWS(wp) + if (wp->w_p_diff && wp != curwin) + { + redraw_win_later(wp, UPD_VALID); + wlnum = diff_lnum_win(lnum, wp); + if (wlnum > 0) + changedOneline(wp->w_buffer, wlnum); + } + } +#endif +} + +/* + * Like changed_bytes() but also adjust text properties for "added" bytes. + * When "added" is negative text was deleted. + */ + void +inserted_bytes(linenr_T lnum, colnr_T col, int added UNUSED) +{ +#ifdef FEAT_PROP_POPUP + if (curbuf->b_has_textprop && added != 0) + adjust_prop_columns(lnum, col, added, 0); +#endif + + changed_bytes(lnum, col); +} + +/* + * Appended "count" lines below line "lnum" in the current buffer. + * Must be called AFTER the change and after mark_adjust(). + * Takes care of marking the buffer to be redrawn and sets the changed flag. + */ + void +appended_lines(linenr_T lnum, long count) +{ + changed_lines(lnum + 1, 0, lnum + 1, count); +} + +/* + * Like appended_lines(), but adjust marks first. + */ + void +appended_lines_mark(linenr_T lnum, long count) +{ + mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L); + changed_lines(lnum + 1, 0, lnum + 1, count); +} + +/* + * Deleted "count" lines at line "lnum" in the current buffer. + * Must be called AFTER the change and after mark_adjust(). + * Takes care of marking the buffer to be redrawn and sets the changed flag. + */ + void +deleted_lines(linenr_T lnum, long count) +{ + changed_lines(lnum, 0, lnum + count, -count); +} + +/* + * Like deleted_lines(), but adjust marks first. + * Make sure the cursor is on a valid line before calling, a GUI callback may + * be triggered to display the cursor. + */ + void +deleted_lines_mark(linenr_T lnum, long count) +{ + mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count); + changed_lines(lnum, 0, lnum + count, -count); +} + +/* + * Marks the area to be redrawn after a change. + * Consider also calling changed_line_display_buf(). + */ + void +changed_lines_buf( + buf_T *buf, + linenr_T lnum, // first line with change + linenr_T lnume, // line below last changed line + long xtra) // number of extra lines (negative when deleting) +{ + if (buf->b_mod_set) + { + // find the maximum area that must be redisplayed + if (lnum < buf->b_mod_top) + buf->b_mod_top = lnum; + if (lnum < buf->b_mod_bot) + { + // adjust old bot position for xtra lines + buf->b_mod_bot += xtra; + if (buf->b_mod_bot < lnum) + buf->b_mod_bot = lnum; + } + if (lnume + xtra > buf->b_mod_bot) + buf->b_mod_bot = lnume + xtra; + buf->b_mod_xlines += xtra; + } + else + { + // set the area that must be redisplayed + buf->b_mod_set = TRUE; + buf->b_mod_top = lnum; + buf->b_mod_bot = lnume + xtra; + buf->b_mod_xlines = xtra; + } +} + +/* + * Changed lines for the current buffer. + * Must be called AFTER the change and after mark_adjust(). + * - mark the buffer changed by calling changed() + * - mark the windows on this buffer to be redisplayed + * - invalidate cached values + * "lnum" is the first line that needs displaying, "lnume" the first line + * below the changed lines (BEFORE the change). + * When only inserting lines, "lnum" and "lnume" are equal. + * Takes care of calling changed() and updating b_mod_*. + * Careful: may trigger autocommands that reload the buffer. + */ + void +changed_lines( + linenr_T lnum, // first line with change + colnr_T col, // column in first line with change + linenr_T lnume, // line below last changed line + long xtra) // number of extra lines (negative when deleting) +{ + changed_lines_buf(curbuf, lnum, lnume, xtra); + +#ifdef FEAT_DIFF + if (xtra == 0 && curwin->w_p_diff && !diff_internal()) + { + // When the number of lines doesn't change then mark_adjust() isn't + // called and other diff buffers still need to be marked for + // displaying. + win_T *wp; + linenr_T wlnum; + + FOR_ALL_WINDOWS(wp) + if (wp->w_p_diff && wp != curwin) + { + redraw_win_later(wp, UPD_VALID); + wlnum = diff_lnum_win(lnum, wp); + if (wlnum > 0) + changed_lines_buf(wp->w_buffer, wlnum, + lnume - lnum + wlnum, 0L); + } + } +#endif + + changed_common(lnum, col, lnume, xtra); +} + +/* + * Called when the changed flag must be reset for buffer "buf". + * When "ff" is TRUE also reset 'fileformat'. + * When "always_inc_changedtick" is TRUE b:changedtick is incremented also when + * the changed flag was off. + */ + void +unchanged(buf_T *buf, int ff, int always_inc_changedtick) +{ + if (buf->b_changed || (ff && file_ff_differs(buf, FALSE))) + { + buf->b_changed = 0; + ml_setflags(buf); + if (ff) + save_file_ff(buf); + check_status(buf); + redraw_tabline = TRUE; + need_maketitle = TRUE; // set window title later + ++CHANGEDTICK(buf); + } + else if (always_inc_changedtick) + ++CHANGEDTICK(buf); +#ifdef FEAT_NETBEANS_INTG + netbeans_unmodified(buf); +#endif +} + +/* + * Save the current values of 'fileformat' and 'fileencoding', so that we know + * the file must be considered changed when the value is different. + */ + void +save_file_ff(buf_T *buf) +{ + buf->b_start_ffc = *buf->b_p_ff; + buf->b_start_eof = buf->b_p_eof; + buf->b_start_eol = buf->b_p_eol; + buf->b_start_bomb = buf->b_p_bomb; + + // Only use free/alloc when necessary, they take time. + if (buf->b_start_fenc == NULL + || STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0) + { + vim_free(buf->b_start_fenc); + buf->b_start_fenc = vim_strsave(buf->b_p_fenc); + } +} + +/* + * Return TRUE if 'fileformat' and/or 'fileencoding' has a different value + * from when editing started (save_file_ff() called). + * Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was + * changed and 'binary' is not set. + * Also when 'endofline' was changed and 'fixeol' is not set. + * When "ignore_empty" is true don't consider a new, empty buffer to be + * changed. + */ + int +file_ff_differs(buf_T *buf, int ignore_empty) +{ + // In a buffer that was never loaded the options are not valid. + if (buf->b_flags & BF_NEVERLOADED) + return FALSE; + if (ignore_empty + && (buf->b_flags & BF_NEW) + && buf->b_ml.ml_line_count == 1 + && *ml_get_buf(buf, (linenr_T)1, FALSE) == NUL) + return FALSE; + if (buf->b_start_ffc != *buf->b_p_ff) + return TRUE; + if ((buf->b_p_bin || !buf->b_p_fixeol) + && (buf->b_start_eof != buf->b_p_eof + || buf->b_start_eol != buf->b_p_eol)) + return TRUE; + if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb) + return TRUE; + if (buf->b_start_fenc == NULL) + return (*buf->b_p_fenc != NUL); + return (STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0); +} + +/* + * Insert string "p" at the cursor position. Stops at a NUL byte. + * Handles Replace mode and multi-byte characters. + */ + void +ins_bytes(char_u *p) +{ + ins_bytes_len(p, (int)STRLEN(p)); +} + +/* + * Insert string "p" with length "len" at the cursor position. + * Handles Replace mode and multi-byte characters. + */ + void +ins_bytes_len(char_u *p, int len) +{ + int i; + int n; + + if (has_mbyte) + for (i = 0; i < len; i += n) + { + if (enc_utf8) + // avoid reading past p[len] + n = utfc_ptr2len_len(p + i, len - i); + else + n = (*mb_ptr2len)(p + i); + ins_char_bytes(p + i, n); + } + else + for (i = 0; i < len; ++i) + ins_char(p[i]); +} + +/* + * Insert or replace a single character at the cursor position. + * When in MODE_REPLACE or MODE_VREPLACE state, replace any existing character. + * Caller must have prepared for undo. + * For multi-byte characters we get the whole character, the caller must + * convert bytes to a character. + */ + void +ins_char(int c) +{ + char_u buf[MB_MAXBYTES + 1]; + int n = (*mb_char2bytes)(c, buf); + + // When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte. + // Happens for CTRL-Vu9900. + if (buf[0] == 0) + buf[0] = '\n'; + + ins_char_bytes(buf, n); +} + + void +ins_char_bytes(char_u *buf, int charlen) +{ + int c = buf[0]; + int newlen; // nr of bytes inserted + int oldlen; // nr of bytes deleted (0 when not replacing) + char_u *p; + char_u *newp; + char_u *oldp; + int linelen; // length of old line including NUL + colnr_T col; + linenr_T lnum = curwin->w_cursor.lnum; + int i; + + // Break tabs if needed. + if (virtual_active() && curwin->w_cursor.coladd > 0) + coladvance_force(getviscol()); + + col = curwin->w_cursor.col; + oldp = ml_get(lnum); + linelen = (int)STRLEN(oldp) + 1; + + // The lengths default to the values for when not replacing. + oldlen = 0; + newlen = charlen; + + if (State & REPLACE_FLAG) + { + if (State & VREPLACE_FLAG) + { + colnr_T new_vcol = 0; // init for GCC + colnr_T vcol; + int old_list; + + // Disable 'list' temporarily, unless 'cpo' contains the 'L' flag. + // Returns the old value of list, so when finished, + // curwin->w_p_list should be set back to this. + old_list = curwin->w_p_list; + if (old_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) + curwin->w_p_list = FALSE; + + // In virtual replace mode each character may replace one or more + // characters (zero if it's a TAB). Count the number of bytes to + // be deleted to make room for the new character, counting screen + // cells. May result in adding spaces to fill a gap. + getvcol(curwin, &curwin->w_cursor, NULL, &vcol, NULL); + new_vcol = vcol + chartabsize(buf, vcol); + while (oldp[col + oldlen] != NUL && vcol < new_vcol) + { + vcol += chartabsize(oldp + col + oldlen, vcol); + // Don't need to remove a TAB that takes us to the right + // position. + if (vcol > new_vcol && oldp[col + oldlen] == TAB) + break; + oldlen += (*mb_ptr2len)(oldp + col + oldlen); + // Deleted a bit too much, insert spaces. + if (vcol > new_vcol) + newlen += vcol - new_vcol; + } + curwin->w_p_list = old_list; + } + else if (oldp[col] != NUL) + { + // normal replace + oldlen = (*mb_ptr2len)(oldp + col); + } + + + // Push the replaced bytes onto the replace stack, so that they can be + // put back when BS is used. The bytes of a multi-byte character are + // done the other way around, so that the first byte is popped off + // first (it tells the byte length of the character). + replace_push(NUL); + for (i = 0; i < oldlen; ++i) + { + if (has_mbyte) + i += replace_push_mb(oldp + col + i) - 1; + else + replace_push(oldp[col + i]); + } + } + + newp = alloc(linelen + newlen - oldlen); + if (newp == NULL) + return; + + // Copy bytes before the cursor. + if (col > 0) + mch_memmove(newp, oldp, (size_t)col); + + // Copy bytes after the changed character(s). + p = newp + col; + if (linelen > col + oldlen) + mch_memmove(p + newlen, oldp + col + oldlen, + (size_t)(linelen - col - oldlen)); + + // Insert or overwrite the new character. + mch_memmove(p, buf, charlen); + i = charlen; + + // Fill with spaces when necessary. + while (i < newlen) + p[i++] = ' '; + + // Replace the line in the buffer. + ml_replace(lnum, newp, FALSE); + + // mark the buffer as changed and prepare for displaying + changed_bytes(lnum, col); +#ifdef FEAT_PROP_POPUP + if (curbuf->b_has_textprop && newlen != oldlen) + adjust_prop_columns(lnum, col, newlen - oldlen, + State & REPLACE_FLAG ? APC_SUBSTITUTE : 0); +#endif + + // If we're in Insert or Replace mode and 'showmatch' is set, then briefly + // show the match for right parens and braces. + if (p_sm && (State & MODE_INSERT) + && msg_silent == 0 + && !ins_compl_active()) + { + if (has_mbyte) + showmatch(mb_ptr2char(buf)); + else + showmatch(c); + } + +#ifdef FEAT_RIGHTLEFT + if (!p_ri || (State & REPLACE_FLAG)) +#endif + { + // Normal insert: move cursor right + curwin->w_cursor.col += charlen; + } + + // TODO: should try to update w_row here, to avoid recomputing it later. +} + +/* + * Insert a string at the cursor position. + * Note: Does NOT handle Replace mode. + * Caller must have prepared for undo. + */ + void +ins_str(char_u *s) +{ + char_u *oldp, *newp; + int newlen = (int)STRLEN(s); + int oldlen; + colnr_T col; + linenr_T lnum = curwin->w_cursor.lnum; + + if (virtual_active() && curwin->w_cursor.coladd > 0) + coladvance_force(getviscol()); + + col = curwin->w_cursor.col; + oldp = ml_get(lnum); + oldlen = (int)STRLEN(oldp); + + newp = alloc(oldlen + newlen + 1); + if (newp == NULL) + return; + if (col > 0) + mch_memmove(newp, oldp, (size_t)col); + mch_memmove(newp + col, s, (size_t)newlen); + mch_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1)); + ml_replace(lnum, newp, FALSE); + inserted_bytes(lnum, col, newlen); + curwin->w_cursor.col += newlen; +} + +/* + * Delete one character under the cursor. + * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line. + * Caller must have prepared for undo. + * + * return FAIL for failure, OK otherwise + */ + int +del_char(int fixpos) +{ + if (has_mbyte) + { + // Make sure the cursor is at the start of a character. + mb_adjust_cursor(); + if (*ml_get_cursor() == NUL) + return FAIL; + return del_chars(1L, fixpos); + } + return del_bytes(1L, fixpos, TRUE); +} + +/* + * Like del_bytes(), but delete characters instead of bytes. + */ + int +del_chars(long count, int fixpos) +{ + long bytes = 0; + long i; + char_u *p; + int l; + + p = ml_get_cursor(); + for (i = 0; i < count && *p != NUL; ++i) + { + l = (*mb_ptr2len)(p); + bytes += l; + p += l; + } + return del_bytes(bytes, fixpos, TRUE); +} + +/* + * Delete "count" bytes under the cursor. + * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line. + * Caller must have prepared for undo. + * + * Return FAIL for failure, OK otherwise. + */ + int +del_bytes( + long count, + int fixpos_arg, + int use_delcombine UNUSED) // 'delcombine' option applies +{ + char_u *oldp, *newp; + colnr_T oldlen; + colnr_T newlen; + linenr_T lnum = curwin->w_cursor.lnum; + colnr_T col = curwin->w_cursor.col; + int alloc_newp; + long movelen; + int fixpos = fixpos_arg; + + oldp = ml_get(lnum); + oldlen = (int)STRLEN(oldp); + + // Can't do anything when the cursor is on the NUL after the line. + if (col >= oldlen) + return FAIL; + + // If "count" is zero there is nothing to do. + if (count == 0) + return OK; + + // If "count" is negative the caller must be doing something wrong. + if (count < 1) + { + siemsg(e_invalid_count_for_del_bytes_nr, count); + return FAIL; + } + + // If 'delcombine' is set and deleting (less than) one character, only + // delete the last combining character. + if (p_deco && use_delcombine && enc_utf8 + && utfc_ptr2len(oldp + col) >= count) + { + int cc[MAX_MCO]; + int n; + + (void)utfc_ptr2char(oldp + col, cc); + if (cc[0] != NUL) + { + // Find the last composing char, there can be several. + n = col; + do + { + col = n; + count = utf_ptr2len(oldp + n); + n += count; + } while (UTF_COMPOSINGLIKE(oldp + col, oldp + n)); + fixpos = 0; + } + } + + // When count is too big, reduce it. + movelen = (long)oldlen - (long)col - count + 1; // includes trailing NUL + if (movelen <= 1) + { + // If we just took off the last character of a non-blank line, and + // fixpos is TRUE, we don't want to end up positioned at the NUL, + // unless "restart_edit" is set or 'virtualedit' contains "onemore". + if (col > 0 && fixpos && restart_edit == 0 + && (get_ve_flags() & VE_ONEMORE) == 0) + { + --curwin->w_cursor.col; + curwin->w_cursor.coladd = 0; + if (has_mbyte) + curwin->w_cursor.col -= + (*mb_head_off)(oldp, oldp + curwin->w_cursor.col); + } + count = oldlen - col; + movelen = 1; + } + newlen = oldlen - count; + + // If the old line has been allocated the deletion can be done in the + // existing line. Otherwise a new line has to be allocated + // Can't do this when using Netbeans, because we would need to invoke + // netbeans_removed(), which deallocates the line. Let ml_replace() take + // care of notifying Netbeans. +#ifdef FEAT_NETBEANS_INTG + if (netbeans_active()) + alloc_newp = TRUE; + else +#endif + alloc_newp = !ml_line_alloced(); // check if oldp was allocated + if (!alloc_newp) + newp = oldp; // use same allocated memory + else + { // need to allocate a new line + newp = alloc(newlen + 1); + if (newp == NULL) + return FAIL; + mch_memmove(newp, oldp, (size_t)col); + } + mch_memmove(newp + col, oldp + col + count, (size_t)movelen); + if (alloc_newp) + ml_replace(lnum, newp, FALSE); +#ifdef FEAT_PROP_POPUP + else + { + // Also move any following text properties. + if (oldlen + 1 < curbuf->b_ml.ml_line_len) + mch_memmove(newp + newlen + 1, oldp + oldlen + 1, + (size_t)curbuf->b_ml.ml_line_len - oldlen - 1); + curbuf->b_ml.ml_line_len -= count; + } +#endif + + // mark the buffer as changed and prepare for displaying + inserted_bytes(lnum, col, -count); + + return OK; +} + +/* + * open_line: Add a new line below or above the current line. + * + * For MODE_VREPLACE state, we only add a new line when we get to the end of + * the file, otherwise we just start replacing the next line. + * + * Caller must take care of undo. Since MODE_VREPLACE may affect any number of + * lines however, it may call u_save_cursor() again when starting to change a + * new line. + * "flags": OPENLINE_DELSPACES delete spaces after cursor + * OPENLINE_DO_COM format comments + * OPENLINE_KEEPTRAIL keep trailing spaces + * OPENLINE_MARKFIX adjust mark positions after the line break + * OPENLINE_COM_LIST format comments with list or 2nd line indent + * + * "second_line_indent": indent for after ^^D in Insert mode or if flag + * OPENLINE_COM_LIST + * "did_do_comment" is set to TRUE when intentionally putting the comment + * leader in front of the new line. + * + * Return OK for success, FAIL for failure + */ + int +open_line( + int dir, // FORWARD or BACKWARD + int flags, + int second_line_indent, + int *did_do_comment UNUSED) +{ + char_u *saved_line; // copy of the original line + char_u *next_line = NULL; // copy of the next line + char_u *p_extra = NULL; // what goes to next line + int less_cols = 0; // less columns for mark in new line + int less_cols_off = 0; // columns to skip for mark and + // textprop adjustment + pos_T old_cursor; // old cursor position + int newcol = 0; // new cursor column + int newindent = 0; // auto-indent of the new line + int n; + int trunc_line = FALSE; // truncate current line afterwards + int retval = FAIL; // return value + int extra_len = 0; // length of p_extra string + int lead_len; // length of comment leader + int comment_start = 0; // start index of the comment leader + char_u *lead_flags; // position in 'comments' for comment leader + char_u *leader = NULL; // copy of comment leader + char_u *allocated = NULL; // allocated memory + char_u *p; + int saved_char = NUL; // init for GCC + pos_T *pos; + int do_cindent; + int do_si = may_do_si(); + int no_si = FALSE; // reset did_si afterwards + int first_char = NUL; // init for GCC + int vreplace_mode; + int did_append; // appended a new line + int saved_pi = curbuf->b_p_pi; // copy of preserveindent setting +#ifdef FEAT_PROP_POPUP + int at_eol; // cursor after last character +#endif + + // make a copy of the current line so we can mess with it + saved_line = vim_strsave(ml_get_curline()); + if (saved_line == NULL) // out of memory! + return FALSE; + +#ifdef FEAT_PROP_POPUP + at_eol = curwin->w_cursor.col >= (int)STRLEN(saved_line); +#endif + + if (State & VREPLACE_FLAG) + { + // With MODE_VREPLACE we make a copy of the next line, which we will be + // starting to replace. First make the new line empty and let vim play + // with the indenting and comment leader to its heart's content. Then + // we grab what it ended up putting on the new line, put back the + // original line, and call ins_char() to put each new character onto + // the line, replacing what was there before and pushing the right + // stuff onto the replace stack. -- webb. + if (curwin->w_cursor.lnum < orig_line_count) + next_line = vim_strsave(ml_get(curwin->w_cursor.lnum + 1)); + else + next_line = vim_strsave((char_u *)""); + if (next_line == NULL) // out of memory! + goto theend; + + // In MODE_VREPLACE state, a NL replaces the rest of the line, and + // starts replacing the next line, so push all of the characters left + // on the line onto the replace stack. We'll push any other characters + // that might be replaced at the start of the next line (due to + // autoindent etc) a bit later. + replace_push(NUL); // Call twice because BS over NL expects it + replace_push(NUL); + p = saved_line + curwin->w_cursor.col; + while (*p != NUL) + { + if (has_mbyte) + p += replace_push_mb(p); + else + replace_push(*p++); + } + saved_line[curwin->w_cursor.col] = NUL; + } + + if ((State & MODE_INSERT) && (State & VREPLACE_FLAG) == 0) + { + p_extra = saved_line + curwin->w_cursor.col; + if (do_si) // need first char after new line break + { + p = skipwhite(p_extra); + first_char = *p; + } + extra_len = (int)STRLEN(p_extra); + saved_char = *p_extra; + *p_extra = NUL; + } + + u_clearline(); // cannot do "U" command when adding lines + did_si = FALSE; + ai_col = 0; + + // If we just did an auto-indent, then we didn't type anything on + // the prior line, and it should be truncated. Do this even if 'ai' is not + // set because automatically inserting a comment leader also sets did_ai. + if (dir == FORWARD && did_ai) + trunc_line = TRUE; + + // If 'autoindent' and/or 'smartindent' is set, try to figure out what + // indent to use for the new line. + if (curbuf->b_p_ai || do_si) + { + // count white space on current line +#ifdef FEAT_VARTABS + newindent = get_indent_str_vtab(saved_line, curbuf->b_p_ts, + curbuf->b_p_vts_array, FALSE); +#else + newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, FALSE); +#endif + if (newindent == 0 && !(flags & OPENLINE_COM_LIST)) + newindent = second_line_indent; // for ^^D command in insert mode + + // Do smart indenting. + // In insert/replace mode (only when dir == FORWARD) + // we may move some text to the next line. If it starts with '{' + // don't add an indent. Fixes inserting a NL before '{' in line + // "if (condition) {" + if (!trunc_line && do_si && *saved_line != NUL + && (p_extra == NULL || first_char != '{')) + { + char_u *ptr; + char_u last_char; + + old_cursor = curwin->w_cursor; + ptr = saved_line; + if (flags & OPENLINE_DO_COM) + lead_len = get_leader_len(ptr, NULL, FALSE, TRUE); + else + lead_len = 0; + if (dir == FORWARD) + { + // Skip preprocessor directives, unless they are + // recognised as comments. + if ( lead_len == 0 && ptr[0] == '#') + { + while (ptr[0] == '#' && curwin->w_cursor.lnum > 1) + ptr = ml_get(--curwin->w_cursor.lnum); + newindent = get_indent(); + } + if (flags & OPENLINE_DO_COM) + lead_len = get_leader_len(ptr, NULL, FALSE, TRUE); + else + lead_len = 0; + if (lead_len > 0) + { + // This case gets the following right: + // /* + // * A comment (read '\' as '/'). + // */ + // #define IN_THE_WAY + // This should line up here; + p = skipwhite(ptr); + if (p[0] == '/' && p[1] == '*') + p++; + if (p[0] == '*') + { + for (p++; *p; p++) + { + if (p[0] == '/' && p[-1] == '*') + { + // End of C comment, indent should line up + // with the line containing the start of + // the comment. + curwin->w_cursor.col = (colnr_T)(p - ptr); + if ((pos = findmatch(NULL, NUL)) != NULL) + { + curwin->w_cursor.lnum = pos->lnum; + newindent = get_indent(); + break; + } + // this may make "ptr" invalid, get it again + ptr = ml_get(curwin->w_cursor.lnum); + p = ptr + curwin->w_cursor.col; + } + } + } + } + else // Not a comment line + { + // Find last non-blank in line + p = ptr + STRLEN(ptr) - 1; + while (p > ptr && VIM_ISWHITE(*p)) + --p; + last_char = *p; + + // find the character just before the '{' or ';' + if (last_char == '{' || last_char == ';') + { + if (p > ptr) + --p; + while (p > ptr && VIM_ISWHITE(*p)) + --p; + } + // Try to catch lines that are split over multiple + // lines. eg: + // if (condition && + // condition) { + // Should line up here! + // } + if (*p == ')') + { + curwin->w_cursor.col = (colnr_T)(p - ptr); + if ((pos = findmatch(NULL, '(')) != NULL) + { + curwin->w_cursor.lnum = pos->lnum; + newindent = get_indent(); + ptr = ml_get_curline(); + } + } + // If last character is '{' do indent, without + // checking for "if" and the like. + if (last_char == '{') + { + did_si = TRUE; // do indent + no_si = TRUE; // don't delete it when '{' typed + } + // Look for "if" and the like, use 'cinwords'. + // Don't do this if the previous line ended in ';' or + // '}'. + else if (last_char != ';' && last_char != '}' + && cin_is_cinword(ptr)) + did_si = TRUE; + } + } + else // dir == BACKWARD + { + // Skip preprocessor directives, unless they are + // recognised as comments. + if (lead_len == 0 && ptr[0] == '#') + { + int was_backslashed = FALSE; + + while ((ptr[0] == '#' || was_backslashed) && + curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) + { + if (*ptr && ptr[STRLEN(ptr) - 1] == '\\') + was_backslashed = TRUE; + else + was_backslashed = FALSE; + ptr = ml_get(++curwin->w_cursor.lnum); + } + if (was_backslashed) + newindent = 0; // Got to end of file + else + newindent = get_indent(); + } + p = skipwhite(ptr); + if (*p == '}') // if line starts with '}': do indent + did_si = TRUE; + else // can delete indent when '{' typed + can_si_back = TRUE; + } + curwin->w_cursor = old_cursor; + } + if (do_si) + can_si = TRUE; + + did_ai = TRUE; + } + + // May do indenting after opening a new line. + do_cindent = !p_paste && (curbuf->b_p_cin +#ifdef FEAT_EVAL + || *curbuf->b_p_inde != NUL +#endif + ) + && in_cinkeys(dir == FORWARD + ? KEY_OPEN_FORW + : KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum)); + + // Find out if the current line starts with a comment leader. + // This may then be inserted in front of the new line. + end_comment_pending = NUL; + if (flags & OPENLINE_DO_COM) + { + lead_len = get_leader_len(saved_line, &lead_flags, + dir == BACKWARD, TRUE); + if (lead_len == 0 && curbuf->b_p_cin && do_cindent && dir == FORWARD + && (!has_format_option(FO_NO_OPEN_COMS) + || (flags & OPENLINE_FORMAT))) + { + // Check for a line comment after code. + comment_start = check_linecomment(saved_line); + if (comment_start != MAXCOL) + { + lead_len = get_leader_len(saved_line + comment_start, + &lead_flags, FALSE, TRUE); + if (lead_len != 0) + { + lead_len += comment_start; + if (did_do_comment != NULL) + *did_do_comment = TRUE; + } + } + } + } + else + lead_len = 0; + if (lead_len > 0) + { + char_u *lead_repl = NULL; // replaces comment leader + int lead_repl_len = 0; // length of *lead_repl + char_u lead_middle[COM_MAX_LEN]; // middle-comment string + char_u lead_end[COM_MAX_LEN]; // end-comment string + char_u *comment_end = NULL; // where lead_end has been found + int extra_space = FALSE; // append extra space + int current_flag; + int require_blank = FALSE; // requires blank after middle + char_u *p2; + + // If the comment leader has the start, middle or end flag, it may not + // be used or may be replaced with the middle leader. + for (p = lead_flags; *p && *p != ':'; ++p) + { + if (*p == COM_BLANK) + { + require_blank = TRUE; + continue; + } + if (*p == COM_START || *p == COM_MIDDLE) + { + current_flag = *p; + if (*p == COM_START) + { + // Doing "O" on a start of comment does not insert leader. + if (dir == BACKWARD) + { + lead_len = 0; + break; + } + + // find start of middle part + (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ","); + require_blank = FALSE; + } + + // Isolate the strings of the middle and end leader. + while (*p && p[-1] != ':') // find end of middle flags + { + if (*p == COM_BLANK) + require_blank = TRUE; + ++p; + } + (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ","); + + while (*p && p[-1] != ':') // find end of end flags + { + // Check whether we allow automatic ending of comments + if (*p == COM_AUTO_END) + end_comment_pending = -1; // means we want to set it + ++p; + } + n = copy_option_part(&p, lead_end, COM_MAX_LEN, ","); + + if (end_comment_pending == -1) // we can set it now + end_comment_pending = lead_end[n - 1]; + + // If the end of the comment is in the same line, don't use + // the comment leader. + if (dir == FORWARD) + { + for (p = saved_line + lead_len; *p; ++p) + if (STRNCMP(p, lead_end, n) == 0) + { + comment_end = p; + lead_len = 0; + break; + } + } + + // Doing "o" on a start of comment inserts the middle leader. + if (lead_len > 0) + { + if (current_flag == COM_START) + { + lead_repl = lead_middle; + lead_repl_len = (int)STRLEN(lead_middle); + } + + // If we have hit RETURN immediately after the start + // comment leader, then put a space after the middle + // comment leader on the next line. + if (!VIM_ISWHITE(saved_line[lead_len - 1]) + && ((p_extra != NULL + && (int)curwin->w_cursor.col == lead_len) + || (p_extra == NULL + && saved_line[lead_len] == NUL) + || require_blank)) + extra_space = TRUE; + } + break; + } + if (*p == COM_END) + { + // Doing "o" on the end of a comment does not insert leader. + // Remember where the end is, might want to use it to find the + // start (for C-comments). + if (dir == FORWARD) + { + comment_end = skipwhite(saved_line); + lead_len = 0; + break; + } + + // Doing "O" on the end of a comment inserts the middle leader. + // Find the string for the middle leader, searching backwards. + while (p > curbuf->b_p_com && *p != ',') + --p; + for (lead_repl = p; lead_repl > curbuf->b_p_com + && lead_repl[-1] != ':'; --lead_repl) + ; + lead_repl_len = (int)(p - lead_repl); + + // We can probably always add an extra space when doing "O" on + // the comment-end + extra_space = TRUE; + + // Check whether we allow automatic ending of comments + for (p2 = p; *p2 && *p2 != ':'; p2++) + { + if (*p2 == COM_AUTO_END) + end_comment_pending = -1; // means we want to set it + } + if (end_comment_pending == -1) + { + // Find last character in end-comment string + while (*p2 && *p2 != ',') + p2++; + end_comment_pending = p2[-1]; + } + break; + } + if (*p == COM_FIRST) + { + // Comment leader for first line only: Don't repeat leader + // when using "O", blank out leader when using "o". + if (dir == BACKWARD) + lead_len = 0; + else + { + lead_repl = (char_u *)""; + lead_repl_len = 0; + } + break; + } + } + if (lead_len) + { + // allocate buffer (may concatenate p_extra later) + leader = alloc(lead_len + lead_repl_len + extra_space + extra_len + + (second_line_indent > 0 ? second_line_indent : 0) + 1); + allocated = leader; // remember to free it later + + if (leader == NULL) + lead_len = 0; + else + { + int li; + + vim_strncpy(leader, saved_line, lead_len); + + // TODO: handle multi-byte and double width chars + for (li = 0; li < comment_start; ++li) + if (!VIM_ISWHITE(leader[li])) + leader[li] = ' '; + + // Replace leader with lead_repl, right or left adjusted + if (lead_repl != NULL) + { + int c = 0; + int off = 0; + + for (p = lead_flags; *p != NUL && *p != ':'; ) + { + if (*p == COM_RIGHT || *p == COM_LEFT) + c = *p++; + else if (VIM_ISDIGIT(*p) || *p == '-') + off = getdigits(&p); + else + ++p; + } + if (c == COM_RIGHT) // right adjusted leader + { + // find last non-white in the leader to line up with + for (p = leader + lead_len - 1; p > leader + && VIM_ISWHITE(*p); --p) + ; + ++p; + + // Compute the length of the replaced characters in + // screen characters, not bytes. + { + int repl_size = vim_strnsize(lead_repl, + lead_repl_len); + int old_size = 0; + char_u *endp = p; + int l; + + while (old_size < repl_size && p > leader) + { + MB_PTR_BACK(leader, p); + old_size += ptr2cells(p); + } + l = lead_repl_len - (int)(endp - p); + if (l != 0) + mch_memmove(endp + l, endp, + (size_t)((leader + lead_len) - endp)); + lead_len += l; + } + mch_memmove(p, lead_repl, (size_t)lead_repl_len); + if (p + lead_repl_len > leader + lead_len) + p[lead_repl_len] = NUL; + + // blank-out any other chars from the old leader. + while (--p >= leader) + { + int l = mb_head_off(leader, p); + + if (l > 1) + { + p -= l; + if (ptr2cells(p) > 1) + { + p[1] = ' '; + --l; + } + mch_memmove(p + 1, p + l + 1, + (size_t)((leader + lead_len) - (p + l + 1))); + lead_len -= l; + *p = ' '; + } + else if (!VIM_ISWHITE(*p)) + *p = ' '; + } + } + else // left adjusted leader + { + p = skipwhite(leader); + + // Compute the length of the replaced characters in + // screen characters, not bytes. Move the part that is + // not to be overwritten. + { + int repl_size = vim_strnsize(lead_repl, + lead_repl_len); + int i; + int l; + + for (i = 0; i < lead_len && p[i] != NUL; i += l) + { + l = (*mb_ptr2len)(p + i); + if (vim_strnsize(p, i + l) > repl_size) + break; + } + if (i != lead_repl_len) + { + mch_memmove(p + lead_repl_len, p + i, + (size_t)(lead_len - i - (p - leader))); + lead_len += lead_repl_len - i; + } + } + mch_memmove(p, lead_repl, (size_t)lead_repl_len); + + // Replace any remaining non-white chars in the old + // leader by spaces. Keep Tabs, the indent must + // remain the same. + for (p += lead_repl_len; p < leader + lead_len; ++p) + if (!VIM_ISWHITE(*p)) + { + // Don't put a space before a TAB. + if (p + 1 < leader + lead_len && p[1] == TAB) + { + --lead_len; + mch_memmove(p, p + 1, + (leader + lead_len) - p); + } + else + { + int l = (*mb_ptr2len)(p); + + if (l > 1) + { + if (ptr2cells(p) > 1) + { + // Replace a double-wide char with + // two spaces + --l; + *p++ = ' '; + } + mch_memmove(p + 1, p + l, + (leader + lead_len) - p); + lead_len -= l - 1; + } + *p = ' '; + } + } + *p = NUL; + } + + // Recompute the indent, it may have changed. + if (curbuf->b_p_ai || do_si) +#ifdef FEAT_VARTABS + newindent = get_indent_str_vtab(leader, curbuf->b_p_ts, + curbuf->b_p_vts_array, FALSE); +#else + newindent = get_indent_str(leader, + (int)curbuf->b_p_ts, FALSE); +#endif + + // Add the indent offset + if (newindent + off < 0) + { + off = -newindent; + newindent = 0; + } + else + newindent += off; + + // Correct trailing spaces for the shift, so that + // alignment remains equal. + while (off > 0 && lead_len > 0 + && leader[lead_len - 1] == ' ') + { + // Don't do it when there is a tab before the space + if (vim_strchr(skipwhite(leader), '\t') != NULL) + break; + --lead_len; + --off; + } + + // If the leader ends in white space, don't add an + // extra space + if (lead_len > 0 && VIM_ISWHITE(leader[lead_len - 1])) + extra_space = FALSE; + leader[lead_len] = NUL; + } + + if (extra_space) + { + leader[lead_len++] = ' '; + leader[lead_len] = NUL; + } + + newcol = lead_len; + + // if a new indent will be set below, remove the indent that + // is in the comment leader + if (newindent || did_si) + { + while (lead_len && VIM_ISWHITE(*leader)) + { + --lead_len; + --newcol; + ++leader; + } + } + + } + did_si = can_si = FALSE; + } + else if (comment_end != NULL) + { + // We have finished a comment, so we don't use the leader. + // If this was a C-comment and 'ai' or 'si' is set do a normal + // indent to align with the line containing the start of the + // comment. + if (comment_end[0] == '*' && comment_end[1] == '/' && + (curbuf->b_p_ai || do_si)) + { + old_cursor = curwin->w_cursor; + curwin->w_cursor.col = (colnr_T)(comment_end - saved_line); + if ((pos = findmatch(NULL, NUL)) != NULL) + { + curwin->w_cursor.lnum = pos->lnum; + newindent = get_indent(); + } + curwin->w_cursor = old_cursor; + } + } + } + + // (State == MODE_INSERT || State == MODE_REPLACE), only when dir == FORWARD + if (p_extra != NULL) + { + *p_extra = saved_char; // restore char that NUL replaced + + // When 'ai' set or "flags" has OPENLINE_DELSPACES, skip to the first + // non-blank. + // + // When in MODE_REPLACE state, put the deleted blanks on the replace + // stack, preceded by a NUL, so they can be put back when a BS is + // entered. + if (REPLACE_NORMAL(State)) + replace_push(NUL); // end of extra blanks + if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES)) + { + while ((*p_extra == ' ' || *p_extra == '\t') + && (!enc_utf8 + || !utf_iscomposing(utf_ptr2char(p_extra + 1)))) + { + if (REPLACE_NORMAL(State)) + replace_push(*p_extra); + ++p_extra; + ++less_cols_off; + } + } + + // columns for marks adjusted for removed columns + less_cols = (int)(p_extra - saved_line); + } + + if (p_extra == NULL) + p_extra = (char_u *)""; // append empty line + + // concatenate leader and p_extra, if there is a leader + if (lead_len) + { + if (flags & OPENLINE_COM_LIST && second_line_indent > 0) + { + int i; + int padding = second_line_indent + - (newindent + (int)STRLEN(leader)); + + // Here whitespace is inserted after the comment char. + // Below, set_indent(newindent, SIN_INSERT) will insert the + // whitespace needed before the comment char. + for (i = 0; i < padding; i++) + { + STRCAT(leader, " "); + less_cols--; + newcol++; + } + } + STRCAT(leader, p_extra); + p_extra = leader; + did_ai = TRUE; // So truncating blanks works with comments + less_cols -= lead_len; + } + else + end_comment_pending = NUL; // turns out there was no leader + + old_cursor = curwin->w_cursor; + if (dir == BACKWARD) + --curwin->w_cursor.lnum; + if (!(State & VREPLACE_FLAG) || old_cursor.lnum >= orig_line_count) + { + if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_T)0, FALSE) + == FAIL) + goto theend; + // Postpone calling changed_lines(), because it would mess up folding + // with markers. + mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L); + did_append = TRUE; +#ifdef FEAT_PROP_POPUP + if ((State & MODE_INSERT) && (State & VREPLACE_FLAG) == 0) + // Properties after the split move to the next line. + adjust_props_for_split(curwin->w_cursor.lnum, curwin->w_cursor.lnum, + curwin->w_cursor.col + 1, 0, at_eol); +#endif + } + else + { + // In MODE_VREPLACE state we are starting to replace the next line. + curwin->w_cursor.lnum++; + if (curwin->w_cursor.lnum >= Insstart.lnum + vr_lines_changed) + { + // In case we NL to a new line, BS to the previous one, and NL + // again, we don't want to save the new line for undo twice. + (void)u_save_cursor(); // errors are ignored! + vr_lines_changed++; + } + ml_replace(curwin->w_cursor.lnum, p_extra, TRUE); + changed_bytes(curwin->w_cursor.lnum, 0); + curwin->w_cursor.lnum--; + did_append = FALSE; + } + + if (newindent || did_si) + { + ++curwin->w_cursor.lnum; + if (did_si) + { + int sw = (int)get_sw_value(curbuf); + + if (p_sr) + newindent -= newindent % sw; + newindent += sw; + } + // Copy the indent + if (curbuf->b_p_ci) + { + (void)copy_indent(newindent, saved_line); + + // Set the 'preserveindent' option so that any further screwing + // with the line doesn't entirely destroy our efforts to preserve + // it. It gets restored at the function end. + curbuf->b_p_pi = TRUE; + } + else + (void)set_indent(newindent, SIN_INSERT); + less_cols -= curwin->w_cursor.col; + + ai_col = curwin->w_cursor.col; + + // In MODE_REPLACE state, for each character in the new indent, there + // must be a NUL on the replace stack, for when it is deleted with BS + if (REPLACE_NORMAL(State)) + for (n = 0; n < (int)curwin->w_cursor.col; ++n) + replace_push(NUL); + newcol += curwin->w_cursor.col; + if (no_si) + did_si = FALSE; + } + + // In MODE_REPLACE state, for each character in the extra leader, there + // must be a NUL on the replace stack, for when it is deleted with BS. + if (REPLACE_NORMAL(State)) + while (lead_len-- > 0) + replace_push(NUL); + + curwin->w_cursor = old_cursor; + + if (dir == FORWARD) + { + if (trunc_line || (State & MODE_INSERT)) + { + // truncate current line at cursor + saved_line[curwin->w_cursor.col] = NUL; + // Remove trailing white space, unless OPENLINE_KEEPTRAIL used. + if (trunc_line && !(flags & OPENLINE_KEEPTRAIL)) + truncate_spaces(saved_line); + ml_replace(curwin->w_cursor.lnum, saved_line, FALSE); + saved_line = NULL; + if (did_append) + { + changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col, + curwin->w_cursor.lnum + 1, 1L); + did_append = FALSE; + + // Move marks after the line break to the new line. + if (flags & OPENLINE_MARKFIX) + mark_col_adjust(curwin->w_cursor.lnum, + curwin->w_cursor.col + less_cols_off, + 1L, (long)-less_cols, 0); +#ifdef FEAT_PROP_POPUP + // Keep into account the deleted blanks on the new line. + if (curbuf->b_has_textprop && less_cols_off != 0) + adjust_prop_columns(curwin->w_cursor.lnum + 1, 0, + -less_cols_off, 0); +#endif + } + else + changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); + } + + // Put the cursor on the new line. Careful: the scrollup() above may + // have moved w_cursor, we must use old_cursor. + curwin->w_cursor.lnum = old_cursor.lnum + 1; + } + if (did_append) + changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L); + + curwin->w_cursor.col = newcol; + curwin->w_cursor.coladd = 0; + + // In MODE_VREPLACE state, we are handling the replace stack ourselves, so + // stop fixthisline() from doing it (via change_indent()) by telling it + // we're in normal MODE_INSERT state. + if (State & VREPLACE_FLAG) + { + vreplace_mode = State; // So we know to put things right later + State = MODE_INSERT; + } + else + vreplace_mode = 0; + + if (!p_paste) + { + if (leader == NULL + && !use_indentexpr_for_lisp() + && curbuf->b_p_lisp + && curbuf->b_p_ai) + { + // do lisp indenting + fixthisline(get_lisp_indent); + ai_col = (colnr_T)getwhitecols_curline(); + } + else if (do_cindent || (curbuf->b_p_ai && use_indentexpr_for_lisp())) + { + // do 'cindent' or 'indentexpr' indenting + do_c_expr_indent(); + ai_col = (colnr_T)getwhitecols_curline(); + } + } + + if (vreplace_mode != 0) + State = vreplace_mode; + + // Finally, MODE_VREPLACE gets the stuff on the new line, then puts back + // the original line, and inserts the new stuff char by char, pushing old + // stuff onto the replace stack (via ins_char()). + if (State & VREPLACE_FLAG) + { + // Put new line in p_extra + p_extra = vim_strsave(ml_get_curline()); + if (p_extra == NULL) + goto theend; + + // Put back original line + ml_replace(curwin->w_cursor.lnum, next_line, FALSE); + + // Insert new stuff into line again + curwin->w_cursor.col = 0; + curwin->w_cursor.coladd = 0; + ins_bytes(p_extra); // will call changed_bytes() + vim_free(p_extra); + next_line = NULL; + } + + retval = OK; // success! +theend: + curbuf->b_p_pi = saved_pi; + vim_free(saved_line); + vim_free(next_line); + vim_free(allocated); + return retval; +} + +/* + * Delete from cursor to end of line. + * Caller must have prepared for undo. + * If "fixpos" is TRUE fix the cursor position when done. + * + * Return FAIL for failure, OK otherwise. + */ + int +truncate_line(int fixpos) +{ + char_u *newp; + linenr_T lnum = curwin->w_cursor.lnum; + colnr_T col = curwin->w_cursor.col; + char_u *old_line; + int deleted; + + old_line = ml_get(lnum); + if (col == 0) + newp = vim_strsave((char_u *)""); + else + newp = vim_strnsave(old_line, col); + deleted = (int)STRLEN(old_line) - col; + + if (newp == NULL) + return FAIL; + + ml_replace(lnum, newp, FALSE); + + // mark the buffer as changed and prepare for displaying + inserted_bytes(lnum, curwin->w_cursor.col, -deleted); + + // If "fixpos" is TRUE we don't want to end up positioned at the NUL. + if (fixpos && curwin->w_cursor.col > 0) + --curwin->w_cursor.col; + + return OK; +} + +/* + * Delete "nlines" lines at the cursor. + * Saves the lines for undo first if "undo" is TRUE. + */ + void +del_lines(long nlines, int undo) +{ + long n; + linenr_T first = curwin->w_cursor.lnum; + + if (nlines <= 0) + return; + + // save the deleted lines for undo + if (undo && u_savedel(first, nlines) == FAIL) + return; + + for (n = 0; n < nlines; ) + { + if (curbuf->b_ml.ml_flags & ML_EMPTY) // nothing to delete + break; + + ml_delete_flags(first, ML_DEL_MESSAGE); + ++n; + + // If we delete the last line in the file, stop + if (first > curbuf->b_ml.ml_line_count) + break; + } + + // Correct the cursor position before calling deleted_lines_mark(), it may + // trigger a callback to display the cursor. + curwin->w_cursor.col = 0; + check_cursor_lnum(); + + // adjust marks, mark the buffer as changed and prepare for displaying + deleted_lines_mark(first, n); +} diff --git a/src/channel.c b/src/channel.c new file mode 100644 index 0000000..33605d4 --- /dev/null +++ b/src/channel.c @@ -0,0 +1,5314 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * Implements communication through a socket or any file handle. + */ + +#ifdef WIN32 +// Must include winsock2.h before windows.h since it conflicts with winsock.h +// (included in windows.h). +# include +# include +#endif + +#include "vim.h" + +#if defined(FEAT_JOB_CHANNEL) || defined(PROTO) + +// TRUE when netbeans is running with a GUI. +#ifdef FEAT_GUI +# define CH_HAS_GUI (gui.in_use || gui.starting) +#endif + +// Note: when making changes here also adjust configure.ac. +#ifdef MSWIN +// WinSock API is separated from C API, thus we can't use read(), write(), +// errno... +# define SOCK_ERRNO errno = WSAGetLastError() +# undef ECONNREFUSED +# define ECONNREFUSED WSAECONNREFUSED +# undef EWOULDBLOCK +# define EWOULDBLOCK WSAEWOULDBLOCK +# undef EINPROGRESS +# define EINPROGRESS WSAEINPROGRESS +# ifdef EINTR +# undef EINTR +# endif +# define EINTR WSAEINTR +# define sock_write(sd, buf, len) send((SOCKET)sd, buf, len, 0) +# define sock_read(sd, buf, len) recv((SOCKET)sd, buf, len, 0) +# define sock_close(sd) closesocket((SOCKET)sd) +// Support for Unix-domain sockets was added in Windows SDK 17061. +# define UNIX_PATH_MAX 108 +typedef struct sockaddr_un { + ADDRESS_FAMILY sun_family; + char sun_path[UNIX_PATH_MAX]; +} SOCKADDR_UN, *PSOCKADDR_UN; +#else +# include +# include +# include +# include +# include +# ifdef HAVE_LIBGEN_H +# include +# endif +# define SOCK_ERRNO +# define sock_write(sd, buf, len) write(sd, buf, len) +# define sock_read(sd, buf, len) read(sd, buf, len) +# define sock_close(sd) close(sd) +# define fd_read(fd, buf, len) read(fd, buf, len) +# define fd_write(sd, buf, len) write(sd, buf, len) +# define fd_close(sd) close(sd) +#endif + +static void channel_read(channel_T *channel, ch_part_T part, char *func); +static ch_mode_T channel_get_mode(channel_T *channel, ch_part_T part); +static int channel_get_timeout(channel_T *channel, ch_part_T part); +static ch_part_T channel_part_send(channel_T *channel); +static ch_part_T channel_part_read(channel_T *channel); + +#define FOR_ALL_CHANNELS(ch) \ + for ((ch) = first_channel; (ch) != NULL; (ch) = (ch)->ch_next) + +// Whether we are inside channel_parse_messages() or another situation where it +// is safe to invoke callbacks. +static int safe_to_invoke_callback = 0; + +#ifdef MSWIN + static int +fd_read(sock_T fd, char *buf, size_t len) +{ + HANDLE h = (HANDLE)fd; + DWORD nread; + + if (!ReadFile(h, buf, (DWORD)len, &nread, NULL)) + return -1; + return (int)nread; +} + + static int +fd_write(sock_T fd, char *buf, size_t len) +{ + size_t todo = len; + HANDLE h = (HANDLE)fd; + DWORD nwrite, size, done = 0; + OVERLAPPED ov; + + while (todo > 0) + { + if (todo > MAX_NAMED_PIPE_SIZE) + size = MAX_NAMED_PIPE_SIZE; + else + size = (DWORD)todo; + // If the pipe overflows while the job does not read the data, + // WriteFile() will block forever. This abandons the write. + memset(&ov, 0, sizeof(ov)); + nwrite = 0; + if (!WriteFile(h, buf + done, size, &nwrite, &ov)) + { + DWORD err = GetLastError(); + + if (err != ERROR_IO_PENDING) + return -1; + if (!GetOverlappedResult(h, &ov, &nwrite, FALSE)) + return -1; + FlushFileBuffers(h); + } + else if (nwrite == 0) + // WriteFile() returns TRUE but did not write anything. This causes + // a hang, so bail out. + break; + todo -= nwrite; + done += nwrite; + } + return (int)done; +} + + static void +fd_close(sock_T fd) +{ + HANDLE h = (HANDLE)fd; + + CloseHandle(h); +} +#endif + +#ifdef MSWIN +# undef PERROR +# define PERROR(msg) (void)semsg("%s: %s", msg, strerror_win32(errno)) + + static char * +strerror_win32(int eno) +{ + static LPVOID msgbuf = NULL; + char_u *ptr; + + if (msgbuf) + { + LocalFree(msgbuf); + msgbuf = NULL; + } + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + eno, + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), + (LPTSTR) &msgbuf, + 0, + NULL); + if (msgbuf != NULL) + // chomp \r or \n + for (ptr = (char_u *)msgbuf; *ptr; ptr++) + switch (*ptr) + { + case '\r': + STRMOVE(ptr, ptr + 1); + ptr--; + break; + case '\n': + if (*(ptr + 1) == '\0') + *ptr = '\0'; + else + *ptr = ' '; + break; + } + return msgbuf; +} +#endif + +/* + * The list of all allocated channels. + */ +static channel_T *first_channel = NULL; +static int next_ch_id = 0; + +/* + * Allocate a new channel. The refcount is set to 1. + * The channel isn't actually used until it is opened. + * Returns NULL if out of memory. + */ + channel_T * +add_channel(void) +{ + ch_part_T part; + channel_T *channel = ALLOC_CLEAR_ONE(channel_T); + + if (channel == NULL) + return NULL; + + channel->ch_id = next_ch_id++; + ch_log(channel, "Created channel"); + + for (part = PART_SOCK; part < PART_COUNT; ++part) + { + channel->ch_part[part].ch_fd = INVALID_FD; +#ifdef FEAT_GUI_X11 + channel->ch_part[part].ch_inputHandler = (XtInputId)NULL; +#endif +#ifdef FEAT_GUI_GTK + channel->ch_part[part].ch_inputHandler = 0; +#endif + channel->ch_part[part].ch_timeout = 2000; + } + + if (first_channel != NULL) + { + first_channel->ch_prev = channel; + channel->ch_next = first_channel; + } + first_channel = channel; + + channel->ch_refcount = 1; + return channel; +} + + int +has_any_channel(void) +{ + return first_channel != NULL; +} + +/* + * Called when the refcount of a channel is zero. + * Return TRUE if "channel" has a callback and the associated job wasn't + * killed. + */ + int +channel_still_useful(channel_T *channel) +{ + int has_sock_msg; + int has_out_msg; + int has_err_msg; + + // If the job was killed the channel is not expected to work anymore. + if (channel->ch_job_killed && channel->ch_job == NULL) + return FALSE; + + // If there is a close callback it may still need to be invoked. + if (channel->ch_close_cb.cb_name != NULL) + return TRUE; + + // If reading from or a buffer it's still useful. + if (channel->ch_part[PART_IN].ch_bufref.br_buf != NULL) + return TRUE; + + // If there is no callback then nobody can get readahead. If the fd is + // closed and there is no readahead then the callback won't be called. + has_sock_msg = channel->ch_part[PART_SOCK].ch_fd != INVALID_FD + || channel->ch_part[PART_SOCK].ch_head.rq_next != NULL + || channel->ch_part[PART_SOCK].ch_json_head.jq_next != NULL; + has_out_msg = channel->ch_part[PART_OUT].ch_fd != INVALID_FD + || channel->ch_part[PART_OUT].ch_head.rq_next != NULL + || channel->ch_part[PART_OUT].ch_json_head.jq_next != NULL; + has_err_msg = channel->ch_part[PART_ERR].ch_fd != INVALID_FD + || channel->ch_part[PART_ERR].ch_head.rq_next != NULL + || channel->ch_part[PART_ERR].ch_json_head.jq_next != NULL; + return (channel->ch_callback.cb_name != NULL && (has_sock_msg + || has_out_msg || has_err_msg)) + || ((channel->ch_part[PART_OUT].ch_callback.cb_name != NULL + || channel->ch_part[PART_OUT].ch_bufref.br_buf != NULL) + && has_out_msg) + || ((channel->ch_part[PART_ERR].ch_callback.cb_name != NULL + || channel->ch_part[PART_ERR].ch_bufref.br_buf != NULL) + && has_err_msg); +} + +/* + * Return TRUE if "channel" is closeable (i.e. all readable fds are closed). + */ + int +channel_can_close(channel_T *channel) +{ + return channel->ch_to_be_closed == 0; +} + +/* + * Close a channel and free all its resources. + * The "channel" pointer remains valid. + */ + static void +channel_free_contents(channel_T *channel) +{ + channel_close(channel, TRUE); + channel_clear(channel); + ch_log(channel, "Freeing channel"); +} + +/* + * Unlink "channel" from the list of channels and free it. + */ + static void +channel_free_channel(channel_T *channel) +{ + if (channel->ch_next != NULL) + channel->ch_next->ch_prev = channel->ch_prev; + if (channel->ch_prev == NULL) + first_channel = channel->ch_next; + else + channel->ch_prev->ch_next = channel->ch_next; + vim_free(channel); +} + + static void +channel_free(channel_T *channel) +{ + if (in_free_unref_items) + return; + + if (safe_to_invoke_callback == 0) + channel->ch_to_be_freed = TRUE; + else + { + channel_free_contents(channel); + channel_free_channel(channel); + } +} + +/* + * Close a channel and free all its resources if there is no further action + * possible, there is no callback to be invoked or the associated job was + * killed. + * Return TRUE if the channel was freed. + */ + static int +channel_may_free(channel_T *channel) +{ + if (!channel_still_useful(channel)) + { + channel_free(channel); + return TRUE; + } + return FALSE; +} + +/* + * Decrement the reference count on "channel" and maybe free it when it goes + * down to zero. Don't free it if there is a pending action. + * Returns TRUE when the channel is no longer referenced. + */ + int +channel_unref(channel_T *channel) +{ + if (channel != NULL && --channel->ch_refcount <= 0) + return channel_may_free(channel); + return FALSE; +} + + int +free_unused_channels_contents(int copyID, int mask) +{ + int did_free = FALSE; + channel_T *ch; + + // This is invoked from the garbage collector, which only runs at a safe + // point. + ++safe_to_invoke_callback; + + FOR_ALL_CHANNELS(ch) + if (!channel_still_useful(ch) + && (ch->ch_copyID & mask) != (copyID & mask)) + { + // Free the channel and ordinary items it contains, but don't + // recurse into Lists, Dictionaries etc. + channel_free_contents(ch); + did_free = TRUE; + } + + --safe_to_invoke_callback; + return did_free; +} + + void +free_unused_channels(int copyID, int mask) +{ + channel_T *ch; + channel_T *ch_next; + + for (ch = first_channel; ch != NULL; ch = ch_next) + { + ch_next = ch->ch_next; + if (!channel_still_useful(ch) + && (ch->ch_copyID & mask) != (copyID & mask)) + // Free the channel struct itself. + channel_free_channel(ch); + } +} + +#if defined(FEAT_GUI) || defined(PROTO) + +# if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) +/* + * Lookup the channel from the socket. Set "partp" to the fd index. + * Returns NULL when the socket isn't found. + */ + static channel_T * +channel_fd2channel(sock_T fd, ch_part_T *partp) +{ + channel_T *channel; + ch_part_T part; + + if (fd == INVALID_FD) + return NULL; + + FOR_ALL_CHANNELS(channel) + { + for (part = PART_SOCK; part < PART_IN; ++part) + if (channel->ch_part[part].ch_fd == fd) + { + *partp = part; + return channel; + } + } + return NULL; +} + + static void +channel_read_fd(int fd) +{ + channel_T *channel; + ch_part_T part; + + channel = channel_fd2channel(fd, &part); + if (channel == NULL) + ch_error(NULL, "Channel for fd %d not found", fd); + else + channel_read(channel, part, "channel_read_fd"); +} +# endif + +/* + * Read a command from netbeans. + */ +# ifdef FEAT_GUI_X11 + static void +messageFromServerX11(XtPointer clientData, + int *unused1 UNUSED, + XtInputId *unused2 UNUSED) +{ + channel_read_fd((int)(long)clientData); +} +# endif + +# ifdef FEAT_GUI_GTK +# if GTK_CHECK_VERSION(3,0,0) + static gboolean +messageFromServerGtk3(GIOChannel *unused1 UNUSED, + GIOCondition unused2 UNUSED, + gpointer clientData) +{ + channel_read_fd(GPOINTER_TO_INT(clientData)); + return TRUE; // Return FALSE instead in case the event source is to + // be removed after this function returns. +} +# else + static void +messageFromServerGtk2(gpointer clientData, + gint unused1 UNUSED, + GdkInputCondition unused2 UNUSED) +{ + channel_read_fd((int)(long)clientData); +} +# endif +# endif + + static void +channel_gui_register_one(channel_T *channel, ch_part_T part UNUSED) +{ + if (!CH_HAS_GUI) + return; + + // gets stuck in handling events for a not connected channel + if (channel->ch_keep_open) + return; + +# ifdef FEAT_GUI_X11 + // Tell notifier we are interested in being called when there is input on + // the editor connection socket. + if (channel->ch_part[part].ch_inputHandler == (XtInputId)NULL) + { + ch_log(channel, "Registering part %s with fd %d", + ch_part_names[part], channel->ch_part[part].ch_fd); + + channel->ch_part[part].ch_inputHandler = XtAppAddInput( + (XtAppContext)app_context, + channel->ch_part[part].ch_fd, + (XtPointer)(XtInputReadMask + XtInputExceptMask), + messageFromServerX11, + (XtPointer)(long)channel->ch_part[part].ch_fd); + } +# else +# ifdef FEAT_GUI_GTK + // Tell gdk we are interested in being called when there is input on the + // editor connection socket. + if (channel->ch_part[part].ch_inputHandler == 0) + { + ch_log(channel, "Registering part %s with fd %d", + ch_part_names[part], channel->ch_part[part].ch_fd); +# if GTK_CHECK_VERSION(3,0,0) + GIOChannel *chnnl = g_io_channel_unix_new( + (gint)channel->ch_part[part].ch_fd); + + channel->ch_part[part].ch_inputHandler = g_io_add_watch( + chnnl, + G_IO_IN|G_IO_HUP|G_IO_ERR|G_IO_PRI, + messageFromServerGtk3, + GINT_TO_POINTER(channel->ch_part[part].ch_fd)); + + g_io_channel_unref(chnnl); +# else + channel->ch_part[part].ch_inputHandler = gdk_input_add( + (gint)channel->ch_part[part].ch_fd, + (GdkInputCondition) + ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION), + messageFromServerGtk2, + (gpointer)(long)channel->ch_part[part].ch_fd); +# endif + } +# endif +# endif +} + + static void +channel_gui_register(channel_T *channel) +{ + if (channel->CH_SOCK_FD != INVALID_FD) + channel_gui_register_one(channel, PART_SOCK); + if (channel->CH_OUT_FD != INVALID_FD + && channel->CH_OUT_FD != channel->CH_SOCK_FD) + channel_gui_register_one(channel, PART_OUT); + if (channel->CH_ERR_FD != INVALID_FD + && channel->CH_ERR_FD != channel->CH_SOCK_FD + && channel->CH_ERR_FD != channel->CH_OUT_FD) + channel_gui_register_one(channel, PART_ERR); +} + +/* + * Register any of our file descriptors with the GUI event handling system. + * Called when the GUI has started. + */ + void +channel_gui_register_all(void) +{ + channel_T *channel; + + FOR_ALL_CHANNELS(channel) + channel_gui_register(channel); +} + + static void +channel_gui_unregister_one(channel_T *channel UNUSED, ch_part_T part UNUSED) +{ +# ifdef FEAT_GUI_X11 + if (channel->ch_part[part].ch_inputHandler != (XtInputId)NULL) + { + ch_log(channel, "Unregistering part %s", ch_part_names[part]); + XtRemoveInput(channel->ch_part[part].ch_inputHandler); + channel->ch_part[part].ch_inputHandler = (XtInputId)NULL; + } +# else +# ifdef FEAT_GUI_GTK + if (channel->ch_part[part].ch_inputHandler != 0) + { + ch_log(channel, "Unregistering part %s", ch_part_names[part]); +# if GTK_CHECK_VERSION(3,0,0) + g_source_remove(channel->ch_part[part].ch_inputHandler); +# else + gdk_input_remove(channel->ch_part[part].ch_inputHandler); +# endif + channel->ch_part[part].ch_inputHandler = 0; + } +# endif +# endif +} + + static void +channel_gui_unregister(channel_T *channel) +{ + ch_part_T part; + + for (part = PART_SOCK; part < PART_IN; ++part) + channel_gui_unregister_one(channel, part); +} + +#endif // FEAT_GUI + +/* + * For Unix we need to call connect() again after connect() failed. + * On Win32 one time is sufficient. + */ + static int +channel_connect( + channel_T *channel, + const struct sockaddr *server_addr, + int server_addrlen, + int *waittime) +{ + int sd = -1; +#ifdef MSWIN + u_long val = 1; +#endif + + while (TRUE) + { + long elapsed_msec = 0; + int waitnow; + int ret; + + if (sd >= 0) + sock_close(sd); + sd = socket(server_addr->sa_family, SOCK_STREAM, 0); + if (sd == -1) + { + ch_error(channel, "in socket() in channel_connect()."); + PERROR(_(e_socket_in_channel_connect)); + return -1; + } + + if (*waittime >= 0) + { + // Make connect() non-blocking. + if ( +#ifdef MSWIN + ioctlsocket(sd, FIONBIO, &val) < 0 +#else + fcntl(sd, F_SETFL, O_NONBLOCK) < 0 +#endif + ) + { + SOCK_ERRNO; + ch_error(channel, + "channel_connect: Connect failed with errno %d", errno); + sock_close(sd); + return -1; + } + } + + // Try connecting to the server. + ch_log(channel, "Connecting..."); + + ret = connect(sd, server_addr, server_addrlen); + if (ret == 0) + // The connection could be established. + break; + + SOCK_ERRNO; + if (*waittime < 0 || (errno != EWOULDBLOCK + && errno != ECONNREFUSED +#ifdef EINPROGRESS + && errno != EINPROGRESS +#endif + )) + { + ch_error(channel, + "channel_connect: Connect failed with errno %d", errno); + PERROR(_(e_cannot_connect_to_port)); + sock_close(sd); + return -1; + } + else if (errno == ECONNREFUSED) + { + ch_error(channel, "channel_connect: Connection refused"); + sock_close(sd); + return -1; + } + + // Limit the waittime to 50 msec. If it doesn't work within this + // time we close the socket and try creating it again. + waitnow = *waittime > 50 ? 50 : *waittime; + + // If connect() didn't finish then try using select() to wait for the + // connection to be made. For Win32 always use select() to wait. + { + struct timeval tv; + fd_set rfds; + fd_set wfds; +#ifndef MSWIN + int so_error = 0; + socklen_t so_error_len = sizeof(so_error); + struct timeval start_tv; + struct timeval end_tv; +#endif + FD_ZERO(&rfds); + FD_SET(sd, &rfds); + FD_ZERO(&wfds); + FD_SET(sd, &wfds); + + tv.tv_sec = waitnow / 1000; + tv.tv_usec = (waitnow % 1000) * 1000; +#ifndef MSWIN + gettimeofday(&start_tv, NULL); +#endif + ch_log(channel, + "Waiting for connection (waiting %d msec)...", waitnow); + + ret = select(sd + 1, &rfds, &wfds, NULL, &tv); + if (ret < 0) + { + SOCK_ERRNO; + ch_error(channel, + "channel_connect: Connect failed with errno %d", errno); + PERROR(_(e_cannot_connect_to_port)); + sock_close(sd); + return -1; + } + +#ifdef MSWIN + // On Win32: select() is expected to work and wait for up to + // "waitnow" msec for the socket to be open. + if (FD_ISSET(sd, &wfds)) + break; + elapsed_msec = waitnow; + if (*waittime > 1 && elapsed_msec < *waittime) + { + *waittime -= elapsed_msec; + continue; + } +#else + // On Linux-like systems: See socket(7) for the behavior + // After putting the socket in non-blocking mode, connect() will + // return EINPROGRESS, select() will not wait (as if writing is + // possible), need to use getsockopt() to check if the socket is + // actually able to connect. + // We detect a failure to connect when either read and write fds + // are set. Use getsockopt() to find out what kind of failure. + if (FD_ISSET(sd, &rfds) || FD_ISSET(sd, &wfds)) + { + ret = getsockopt(sd, + SOL_SOCKET, SO_ERROR, &so_error, &so_error_len); + if (ret < 0 || (so_error != 0 + && so_error != EWOULDBLOCK + && so_error != ECONNREFUSED +# ifdef EINPROGRESS + && so_error != EINPROGRESS +# endif + )) + { + ch_error(channel, + "channel_connect: Connect failed with errno %d", + so_error); + PERROR(_(e_cannot_connect_to_port)); + sock_close(sd); + return -1; + } + else if (errno == ECONNREFUSED) + { + ch_error(channel, "channel_connect: Connection refused"); + sock_close(sd); + return -1; + } + } + + if (FD_ISSET(sd, &wfds) && so_error == 0) + // Did not detect an error, connection is established. + break; + + gettimeofday(&end_tv, NULL); + elapsed_msec = (end_tv.tv_sec - start_tv.tv_sec) * 1000 + + (end_tv.tv_usec - start_tv.tv_usec) / 1000; +#endif + } + +#ifndef MSWIN + if (*waittime > 1 && elapsed_msec < *waittime) + { + // The port isn't ready but we also didn't get an error. + // This happens when the server didn't open the socket + // yet. Select() may return early, wait until the remaining + // "waitnow" and try again. + waitnow -= elapsed_msec; + *waittime -= elapsed_msec; + if (waitnow > 0) + { + mch_delay((long)waitnow, MCH_DELAY_IGNOREINPUT); + ui_breakcheck(); + *waittime -= waitnow; + } + if (!got_int) + { + if (*waittime <= 0) + // give it one more try + *waittime = 1; + continue; + } + // we were interrupted, behave as if timed out + } +#endif + + // We timed out. + ch_error(channel, "Connection timed out"); + sock_close(sd); + return -1; + } + + if (*waittime >= 0) + { +#ifdef MSWIN + val = 0; + ioctlsocket(sd, FIONBIO, &val); +#else + (void)fcntl(sd, F_SETFL, 0); +#endif + } + + return sd; +} + +/* + * Open a socket channel to the UNIX socket at "path". + * Returns the channel for success. + * Returns NULL for failure. + */ + static channel_T * +channel_open_unix( + const char *path, + void (*nb_close_cb)(void)) +{ + channel_T *channel = NULL; + int sd = -1; + size_t path_len = STRLEN(path); + struct sockaddr_un server; + size_t server_len; + int waittime = -1; + + if (*path == NUL || path_len >= sizeof(server.sun_path)) + { + semsg(_(e_invalid_argument_str), path); + return NULL; + } + + channel = add_channel(); + if (channel == NULL) + { + ch_error(NULL, "Cannot allocate channel."); + return NULL; + } + + CLEAR_FIELD(server); + server.sun_family = AF_UNIX; + STRNCPY(server.sun_path, path, sizeof(server.sun_path) - 1); + + ch_log(channel, "Trying to connect to %s", path); + + server_len = offsetof(struct sockaddr_un, sun_path) + path_len + 1; + sd = channel_connect(channel, (struct sockaddr *)&server, (int)server_len, + &waittime); + + if (sd < 0) + { + channel_free(channel); + return NULL; + } + + ch_log(channel, "Connection made"); + + channel->CH_SOCK_FD = (sock_T)sd; + channel->ch_nb_close_cb = nb_close_cb; + channel->ch_hostname = (char *)vim_strsave((char_u *)path); + channel->ch_port = 0; + channel->ch_to_be_closed |= (1U << PART_SOCK); + +#ifdef FEAT_GUI + channel_gui_register_one(channel, PART_SOCK); +#endif + + return channel; +} + +/* + * Open a socket channel to "hostname":"port". + * "waittime" is the time in msec to wait for the connection. + * When negative wait forever. + * Returns the channel for success. + * Returns NULL for failure. + */ + channel_T * +channel_open( + const char *hostname, + int port, + int waittime, + void (*nb_close_cb)(void)) +{ + int sd = -1; + channel_T *channel = NULL; +#ifdef FEAT_IPV6 + int err; + struct addrinfo hints; + struct addrinfo *res = NULL; + struct addrinfo *addr = NULL; +#else + struct sockaddr_in server; + struct hostent *host = NULL; +#endif + +#ifdef MSWIN + channel_init_winsock(); +#endif + + channel = add_channel(); + if (channel == NULL) + { + ch_error(NULL, "Cannot allocate channel."); + return NULL; + } + + // Get the server internet address and put into addr structure fill in the + // socket address structure and connect to server. +#ifdef FEAT_IPV6 + CLEAR_FIELD(hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; +# if defined(AI_ADDRCONFIG) && defined(AI_V4MAPPED) + hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED; +# endif + // Set port number manually in order to prevent name resolution services + // from being invoked in the environment where AI_NUMERICSERV is not + // defined. + if ((err = getaddrinfo(hostname, NULL, &hints, &res)) != 0) + { + ch_error(channel, "in getaddrinfo() in channel_open()"); + semsg(_(e_getaddrinfo_in_channel_open_str), gai_strerror(err)); + channel_free(channel); + return NULL; + } + + for (addr = res; addr != NULL; addr = addr->ai_next) + { + const char *dst = hostname; +# ifdef HAVE_INET_NTOP + const void *src = NULL; + char buf[NUMBUFLEN]; +# endif + + if (addr->ai_family == AF_INET6) + { + struct sockaddr_in6 *sai = (struct sockaddr_in6 *)addr->ai_addr; + + sai->sin6_port = htons(port); +# ifdef HAVE_INET_NTOP + src = &sai->sin6_addr; +# endif + } + else if (addr->ai_family == AF_INET) + { + struct sockaddr_in *sai = (struct sockaddr_in *)addr->ai_addr; + + sai->sin_port = htons(port); +# ifdef HAVE_INET_NTOP + src = &sai->sin_addr; +#endif + } +# ifdef HAVE_INET_NTOP + if (src != NULL) + { + dst = inet_ntop(addr->ai_family, src, buf, sizeof(buf)); + if (dst == NULL) + dst = hostname; + else if (STRCMP(hostname, dst) != 0) + ch_log(channel, "Resolved %s to %s", hostname, dst); + } +# endif + + ch_log(channel, "Trying to connect to %s port %d", dst, port); + + // On Mac and Solaris a zero timeout almost never works. Waiting for + // one millisecond already helps a lot. Later Mac systems (using IPv6) + // need more time, 15 milliseconds appears to work well. + // Let's do it for all systems, because we don't know why this is + // needed. + if (waittime == 0) + waittime = 15; + + sd = channel_connect(channel, addr->ai_addr, (int)addr->ai_addrlen, + &waittime); + if (sd >= 0) + break; + } + + freeaddrinfo(res); +#else + CLEAR_FIELD(server); + server.sin_family = AF_INET; + server.sin_port = htons(port); + if ((host = gethostbyname(hostname)) == NULL) + { + ch_error(channel, "in gethostbyname() in channel_open()"); + PERROR(_(e_gethostbyname_in_channel_open)); + channel_free(channel); + return NULL; + } + { + char *p; + + // When using host->h_addr_list[0] directly ubsan warns for it to not + // be aligned. First copy the pointer to avoid that. + memcpy(&p, &host->h_addr_list[0], sizeof(p)); + memcpy((char *)&server.sin_addr, p, host->h_length); + } + + ch_log(channel, "Trying to connect to %s port %d", hostname, port); + + // On Mac and Solaris a zero timeout almost never works. At least wait one + // millisecond. Let's do it for all systems, because we don't know why + // this is needed. + if (waittime == 0) + waittime = 1; + + sd = channel_connect(channel, (struct sockaddr *)&server, sizeof(server), + &waittime); +#endif + + if (sd < 0) + { + channel_free(channel); + return NULL; + } + + ch_log(channel, "Connection made"); + + channel->CH_SOCK_FD = (sock_T)sd; + channel->ch_nb_close_cb = nb_close_cb; + channel->ch_hostname = (char *)vim_strsave((char_u *)hostname); + channel->ch_port = port; + channel->ch_to_be_closed |= (1U << PART_SOCK); + +#ifdef FEAT_GUI + channel_gui_register_one(channel, PART_SOCK); +#endif + + return channel; +} + + static void +free_set_callback(callback_T *cbp, callback_T *callback) +{ + free_callback(cbp); + + if (callback->cb_name != NULL && *callback->cb_name != NUL) + copy_callback(cbp, callback); + else + cbp->cb_name = NULL; +} + +/* + * Prepare buffer "buf" for writing channel output to. + */ + static void +prepare_buffer(buf_T *buf) +{ + buf_T *save_curbuf = curbuf; + + buf_copy_options(buf, BCO_ENTER); + curbuf = buf; +#ifdef FEAT_QUICKFIX + set_option_value_give_err((char_u *)"bt", + 0L, (char_u *)"nofile", OPT_LOCAL); + set_option_value_give_err((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL); +#endif + if (curbuf->b_ml.ml_mfp == NULL) + ml_open(curbuf); + curbuf = save_curbuf; +} + +/* + * Find a buffer matching "name" or create a new one. + * Returns NULL if there is something very wrong (error already reported). + */ + static buf_T * +channel_find_buffer(char_u *name, int err, int msg) +{ + buf_T *buf = NULL; + buf_T *save_curbuf = curbuf; + + if (name != NULL && *name != NUL) + { + buf = buflist_findname(name); + if (buf == NULL) + buf = buflist_findname_exp(name); + } + + if (buf != NULL) + return buf; + + buf = buflist_new(name == NULL || *name == NUL ? NULL : name, + NULL, (linenr_T)0, BLN_LISTED | BLN_NEW); + if (buf == NULL) + return NULL; + prepare_buffer(buf); + + curbuf = buf; + if (msg) + ml_replace(1, (char_u *)(err ? "Reading from channel error..." + : "Reading from channel output..."), TRUE); + changed_bytes(1, 0); + curbuf = save_curbuf; + + return buf; +} + +/* + * Set various properties from an "opt" argument. + */ + static void +channel_set_options(channel_T *channel, jobopt_T *opt) +{ + ch_part_T part; + + if (opt->jo_set & JO_MODE) + for (part = PART_SOCK; part < PART_COUNT; ++part) + channel->ch_part[part].ch_mode = opt->jo_mode; + if (opt->jo_set & JO_IN_MODE) + channel->ch_part[PART_IN].ch_mode = opt->jo_in_mode; + if (opt->jo_set & JO_OUT_MODE) + channel->ch_part[PART_OUT].ch_mode = opt->jo_out_mode; + if (opt->jo_set & JO_ERR_MODE) + channel->ch_part[PART_ERR].ch_mode = opt->jo_err_mode; + channel->ch_nonblock = opt->jo_noblock; + + if (opt->jo_set & JO_TIMEOUT) + for (part = PART_SOCK; part < PART_COUNT; ++part) + channel->ch_part[part].ch_timeout = opt->jo_timeout; + if (opt->jo_set & JO_OUT_TIMEOUT) + channel->ch_part[PART_OUT].ch_timeout = opt->jo_out_timeout; + if (opt->jo_set & JO_ERR_TIMEOUT) + channel->ch_part[PART_ERR].ch_timeout = opt->jo_err_timeout; + if (opt->jo_set & JO_BLOCK_WRITE) + channel->ch_part[PART_IN].ch_block_write = 1; + + if (opt->jo_set & JO_CALLBACK) + free_set_callback(&channel->ch_callback, &opt->jo_callback); + if (opt->jo_set & JO_OUT_CALLBACK) + free_set_callback(&channel->ch_part[PART_OUT].ch_callback, + &opt->jo_out_cb); + if (opt->jo_set & JO_ERR_CALLBACK) + free_set_callback(&channel->ch_part[PART_ERR].ch_callback, + &opt->jo_err_cb); + if (opt->jo_set & JO_CLOSE_CALLBACK) + free_set_callback(&channel->ch_close_cb, &opt->jo_close_cb); + channel->ch_drop_never = opt->jo_drop_never; + + if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER) + { + buf_T *buf; + + // writing output to a buffer. Default mode is NL. + if (!(opt->jo_set & JO_OUT_MODE)) + channel->ch_part[PART_OUT].ch_mode = CH_MODE_NL; + if (opt->jo_set & JO_OUT_BUF) + { + buf = buflist_findnr(opt->jo_io_buf[PART_OUT]); + if (buf == NULL) + semsg(_(e_buffer_nr_does_not_exist), + (long)opt->jo_io_buf[PART_OUT]); + } + else + { + int msg = TRUE; + + if (opt->jo_set2 & JO2_OUT_MSG) + msg = opt->jo_message[PART_OUT]; + buf = channel_find_buffer(opt->jo_io_name[PART_OUT], FALSE, msg); + } + if (buf != NULL) + { + if (opt->jo_set & JO_OUT_MODIFIABLE) + channel->ch_part[PART_OUT].ch_nomodifiable = + !opt->jo_modifiable[PART_OUT]; + + if (!buf->b_p_ma && !channel->ch_part[PART_OUT].ch_nomodifiable) + { + emsg(_(e_cannot_make_changes_modifiable_is_off)); + } + else + { + ch_log(channel, "writing out to buffer '%s'", + (char *)buf->b_ffname); + set_bufref(&channel->ch_part[PART_OUT].ch_bufref, buf); + // if the buffer was deleted or unloaded resurrect it + if (buf->b_ml.ml_mfp == NULL) + prepare_buffer(buf); + } + } + } + + if ((opt->jo_set & JO_ERR_IO) && (opt->jo_io[PART_ERR] == JIO_BUFFER + || (opt->jo_io[PART_ERR] == JIO_OUT && (opt->jo_set & JO_OUT_IO) + && opt->jo_io[PART_OUT] == JIO_BUFFER))) + { + buf_T *buf; + + // writing err to a buffer. Default mode is NL. + if (!(opt->jo_set & JO_ERR_MODE)) + channel->ch_part[PART_ERR].ch_mode = CH_MODE_NL; + if (opt->jo_io[PART_ERR] == JIO_OUT) + buf = channel->ch_part[PART_OUT].ch_bufref.br_buf; + else if (opt->jo_set & JO_ERR_BUF) + { + buf = buflist_findnr(opt->jo_io_buf[PART_ERR]); + if (buf == NULL) + semsg(_(e_buffer_nr_does_not_exist), + (long)opt->jo_io_buf[PART_ERR]); + } + else + { + int msg = TRUE; + + if (opt->jo_set2 & JO2_ERR_MSG) + msg = opt->jo_message[PART_ERR]; + buf = channel_find_buffer(opt->jo_io_name[PART_ERR], TRUE, msg); + } + if (buf != NULL) + { + if (opt->jo_set & JO_ERR_MODIFIABLE) + channel->ch_part[PART_ERR].ch_nomodifiable = + !opt->jo_modifiable[PART_ERR]; + if (!buf->b_p_ma && !channel->ch_part[PART_ERR].ch_nomodifiable) + { + emsg(_(e_cannot_make_changes_modifiable_is_off)); + } + else + { + ch_log(channel, "writing err to buffer '%s'", + (char *)buf->b_ffname); + set_bufref(&channel->ch_part[PART_ERR].ch_bufref, buf); + // if the buffer was deleted or unloaded resurrect it + if (buf->b_ml.ml_mfp == NULL) + prepare_buffer(buf); + } + } + } + + channel->ch_part[PART_OUT].ch_io = opt->jo_io[PART_OUT]; + channel->ch_part[PART_ERR].ch_io = opt->jo_io[PART_ERR]; + channel->ch_part[PART_IN].ch_io = opt->jo_io[PART_IN]; +} + +/* + * Implements ch_open(). + */ + static channel_T * +channel_open_func(typval_T *argvars) +{ + char_u *address; + char_u *p; + char *rest; + int port = 0; + int is_ipv6 = FALSE; + int is_unix = FALSE; + jobopt_T opt; + channel_T *channel = NULL; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_opt_dict_arg(argvars, 1) == FAIL)) + return NULL; + + address = tv_get_string(&argvars[0]); + if (argvars[1].v_type != VAR_UNKNOWN + && check_for_nonnull_dict_arg(argvars, 1) == FAIL) + return NULL; + + if (*address == NUL) + { + semsg(_(e_invalid_argument_str), address); + return NULL; + } + + if (!STRNCMP(address, "unix:", 5)) + { + is_unix = TRUE; + address += 5; + } + else if (*address == '[') + { + // ipv6 address + is_ipv6 = TRUE; + p = vim_strchr(address + 1, ']'); + if (p == NULL || *++p != ':') + { + semsg(_(e_invalid_argument_str), address); + return NULL; + } + } + else + { + // ipv4 address + p = vim_strchr(address, ':'); + if (p == NULL) + { + semsg(_(e_invalid_argument_str), address); + return NULL; + } + } + + if (!is_unix) + { + port = strtol((char *)(p + 1), &rest, 10); + if (port <= 0 || port >= 65536 || *rest != NUL) + { + semsg(_(e_invalid_argument_str), address); + return NULL; + } + if (is_ipv6) + { + // strip '[' and ']' + ++address; + *(p - 1) = NUL; + } + else + *p = NUL; + } + + // parse options + clear_job_options(&opt); + opt.jo_mode = CH_MODE_JSON; + opt.jo_timeout = 2000; + if (get_job_options(&argvars[1], &opt, + JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + + (is_unix? 0 : JO_WAITTIME), 0) == FAIL) + goto theend; + if (opt.jo_timeout < 0) + { + emsg(_(e_invalid_argument)); + goto theend; + } + + if (is_unix) + channel = channel_open_unix((char *)address, NULL); + else + channel = channel_open((char *)address, port, opt.jo_waittime, NULL); + if (channel != NULL) + { + opt.jo_set = JO_ALL; + channel_set_options(channel, &opt); + } +theend: + free_job_options(&opt); + return channel; +} + + void +ch_close_part(channel_T *channel, ch_part_T part) +{ + sock_T *fd = &channel->ch_part[part].ch_fd; + + if (*fd == INVALID_FD) + return; + + if (part == PART_SOCK) + sock_close(*fd); + else + { + // When using a pty the same FD is set on multiple parts, only + // close it when the last reference is closed. + if ((part == PART_IN || channel->CH_IN_FD != *fd) + && (part == PART_OUT || channel->CH_OUT_FD != *fd) + && (part == PART_ERR || channel->CH_ERR_FD != *fd)) + { +#ifdef MSWIN + if (channel->ch_named_pipe) + DisconnectNamedPipe((HANDLE)fd); +#endif + fd_close(*fd); + } + } + *fd = INVALID_FD; + + // channel is closed, may want to end the job if it was the last + channel->ch_to_be_closed &= ~(1U << part); +} + + void +channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err) +{ + if (in != INVALID_FD) + { + ch_close_part(channel, PART_IN); + channel->CH_IN_FD = in; +# if defined(UNIX) + // Do not end the job when all output channels are closed, wait until + // the job ended. + if (mch_isatty(in)) + channel->ch_to_be_closed |= (1U << PART_IN); +# endif + } + if (out != INVALID_FD) + { +# if defined(FEAT_GUI) + channel_gui_unregister_one(channel, PART_OUT); +# endif + ch_close_part(channel, PART_OUT); + channel->CH_OUT_FD = out; + channel->ch_to_be_closed |= (1U << PART_OUT); +# if defined(FEAT_GUI) + channel_gui_register_one(channel, PART_OUT); +# endif + } + if (err != INVALID_FD) + { +# if defined(FEAT_GUI) + channel_gui_unregister_one(channel, PART_ERR); +# endif + ch_close_part(channel, PART_ERR); + channel->CH_ERR_FD = err; + channel->ch_to_be_closed |= (1U << PART_ERR); +# if defined(FEAT_GUI) + channel_gui_register_one(channel, PART_ERR); +# endif + } +} + +/* + * Sets the job the channel is associated with and associated options. + * This does not keep a refcount, when the job is freed ch_job is cleared. + */ + void +channel_set_job(channel_T *channel, job_T *job, jobopt_T *options) +{ + channel->ch_job = job; + + channel_set_options(channel, options); + + if (job->jv_in_buf == NULL) + return; + + chanpart_T *in_part = &channel->ch_part[PART_IN]; + + set_bufref(&in_part->ch_bufref, job->jv_in_buf); + ch_log(channel, "reading from buffer '%s'", + (char *)in_part->ch_bufref.br_buf->b_ffname); + if (options->jo_set & JO_IN_TOP) + { + if (options->jo_in_top == 0 && !(options->jo_set & JO_IN_BOT)) + { + // Special mode: send last-but-one line when appending a line + // to the buffer. + in_part->ch_bufref.br_buf->b_write_to_channel = TRUE; + in_part->ch_buf_append = TRUE; + in_part->ch_buf_top = + in_part->ch_bufref.br_buf->b_ml.ml_line_count + 1; + } + else + in_part->ch_buf_top = options->jo_in_top; + } + else + in_part->ch_buf_top = 1; + if (options->jo_set & JO_IN_BOT) + in_part->ch_buf_bot = options->jo_in_bot; + else + in_part->ch_buf_bot = in_part->ch_bufref.br_buf->b_ml.ml_line_count; +} + +/* + * Set the callback for "channel"/"part" for the response with "id". + */ + static void +channel_set_req_callback( + channel_T *channel, + ch_part_T part, + callback_T *callback, + int id) +{ + cbq_T *head = &channel->ch_part[part].ch_cb_head; + cbq_T *item = ALLOC_ONE(cbq_T); + + if (item == NULL) + return; + + copy_callback(&item->cq_callback, callback); + item->cq_seq_nr = id; + item->cq_prev = head->cq_prev; + head->cq_prev = item; + item->cq_next = NULL; + if (item->cq_prev == NULL) + head->cq_next = item; + else + item->cq_prev->cq_next = item; +} + + static void +write_buf_line(buf_T *buf, linenr_T lnum, channel_T *channel) +{ + char_u *line = ml_get_buf(buf, lnum, FALSE); + int len = (int)STRLEN(line); + char_u *p; + int i; + + // Need to make a copy to be able to append a NL. + if ((p = alloc(len + 2)) == NULL) + return; + memcpy((char *)p, (char *)line, len); + + if (channel->ch_write_text_mode) + p[len] = CAR; + else + { + for (i = 0; i < len; ++i) + if (p[i] == NL) + p[i] = NUL; + + p[len] = NL; + } + p[len + 1] = NUL; + channel_send(channel, PART_IN, p, len + 1, "write_buf_line"); + vim_free(p); +} + +/* + * Return TRUE if "channel" can be written to. + * Returns FALSE if the input is closed or the write would block. + */ + static int +can_write_buf_line(channel_T *channel) +{ + chanpart_T *in_part = &channel->ch_part[PART_IN]; + + if (in_part->ch_fd == INVALID_FD) + return FALSE; // pipe was closed + + // for testing: block every other attempt to write + if (in_part->ch_block_write == 1) + in_part->ch_block_write = -1; + else if (in_part->ch_block_write == -1) + in_part->ch_block_write = 1; + + // TODO: Win32 implementation, probably using WaitForMultipleObjects() +#ifndef MSWIN + { +# if defined(HAVE_SELECT) + struct timeval tval; + fd_set wfds; + int ret; + + FD_ZERO(&wfds); + FD_SET((int)in_part->ch_fd, &wfds); + tval.tv_sec = 0; + tval.tv_usec = 0; + for (;;) + { + ret = select((int)in_part->ch_fd + 1, NULL, &wfds, NULL, &tval); +# ifdef EINTR + SOCK_ERRNO; + if (ret == -1 && errno == EINTR) + continue; +# endif + if (ret <= 0 || in_part->ch_block_write == 1) + { + if (ret > 0) + ch_log(channel, "FAKED Input not ready for writing"); + else + ch_log(channel, "Input not ready for writing"); + return FALSE; + } + break; + } +# else + struct pollfd fds; + + fds.fd = in_part->ch_fd; + fds.events = POLLOUT; + if (poll(&fds, 1, 0) <= 0) + { + ch_log(channel, "Input not ready for writing"); + return FALSE; + } + if (in_part->ch_block_write == 1) + { + ch_log(channel, "FAKED Input not ready for writing"); + return FALSE; + } +# endif + } +#endif + return TRUE; +} + +/* + * Write any buffer lines to the input channel. + */ + void +channel_write_in(channel_T *channel) +{ + chanpart_T *in_part = &channel->ch_part[PART_IN]; + linenr_T lnum; + buf_T *buf = in_part->ch_bufref.br_buf; + int written = 0; + + if (buf == NULL || in_part->ch_buf_append) + return; // no buffer or using appending + if (!bufref_valid(&in_part->ch_bufref) || buf->b_ml.ml_mfp == NULL) + { + // buffer was wiped out or unloaded + ch_log(channel, "input buffer has been wiped out"); + in_part->ch_bufref.br_buf = NULL; + return; + } + + for (lnum = in_part->ch_buf_top; lnum <= in_part->ch_buf_bot + && lnum <= buf->b_ml.ml_line_count; ++lnum) + { + if (!can_write_buf_line(channel)) + break; + write_buf_line(buf, lnum, channel); + ++written; + } + + if (written == 1) + ch_log(channel, "written line %d to channel", (int)lnum - 1); + else if (written > 1) + ch_log(channel, "written %d lines to channel", written); + + in_part->ch_buf_top = lnum; + if (lnum > buf->b_ml.ml_line_count || lnum > in_part->ch_buf_bot) + { +#if defined(FEAT_TERMINAL) + // Send CTRL-D or "eof_chars" to close stdin on MS-Windows. + if (channel->ch_job != NULL) + term_send_eof(channel); +#endif + + // Writing is done, no longer need the buffer. + in_part->ch_bufref.br_buf = NULL; + ch_log(channel, "Finished writing all lines to channel"); + + // Close the pipe/socket, so that the other side gets EOF. + ch_close_part(channel, PART_IN); + } + else + ch_log(channel, "Still %ld more lines to write", + (long)(buf->b_ml.ml_line_count - lnum + 1)); +} + +/* + * Handle buffer "buf" being freed, remove it from any channels. + */ + void +channel_buffer_free(buf_T *buf) +{ + channel_T *channel; + ch_part_T part; + + FOR_ALL_CHANNELS(channel) + for (part = PART_SOCK; part < PART_COUNT; ++part) + { + chanpart_T *ch_part = &channel->ch_part[part]; + + if (ch_part->ch_bufref.br_buf == buf) + { + ch_log(channel, "%s buffer has been wiped out", + ch_part_names[part]); + ch_part->ch_bufref.br_buf = NULL; + } + } +} + +/* + * Write any lines waiting to be written to "channel". + */ + static void +channel_write_input(channel_T *channel) +{ + chanpart_T *in_part = &channel->ch_part[PART_IN]; + + if (in_part->ch_writeque.wq_next != NULL) + channel_send(channel, PART_IN, (char_u *)"", 0, "channel_write_input"); + else if (in_part->ch_bufref.br_buf != NULL) + { + if (in_part->ch_buf_append) + channel_write_new_lines(in_part->ch_bufref.br_buf); + else + channel_write_in(channel); + } +} + +/* + * Write any lines waiting to be written to a channel. + */ + void +channel_write_any_lines(void) +{ + channel_T *channel; + + FOR_ALL_CHANNELS(channel) + channel_write_input(channel); +} + +/* + * Write appended lines above the last one in "buf" to the channel. + */ + void +channel_write_new_lines(buf_T *buf) +{ + channel_T *channel; + int found_one = FALSE; + + // There could be more than one channel for the buffer, loop over all of + // them. + FOR_ALL_CHANNELS(channel) + { + chanpart_T *in_part = &channel->ch_part[PART_IN]; + linenr_T lnum; + int written = 0; + + if (in_part->ch_bufref.br_buf == buf && in_part->ch_buf_append) + { + if (in_part->ch_fd == INVALID_FD) + continue; // pipe was closed + found_one = TRUE; + for (lnum = in_part->ch_buf_bot; lnum < buf->b_ml.ml_line_count; + ++lnum) + { + if (!can_write_buf_line(channel)) + break; + write_buf_line(buf, lnum, channel); + ++written; + } + + if (written == 1) + ch_log(channel, "written line %d to channel", (int)lnum - 1); + else if (written > 1) + ch_log(channel, "written %d lines to channel", written); + if (lnum < buf->b_ml.ml_line_count) + ch_log(channel, "Still %ld more lines to write", + (long)(buf->b_ml.ml_line_count - lnum)); + + in_part->ch_buf_bot = lnum; + } + } + if (!found_one) + buf->b_write_to_channel = FALSE; +} + +/* + * Invoke the "callback" on channel "channel". + * This does not redraw but sets channel_need_redraw; + */ + static void +invoke_callback(channel_T *channel, callback_T *callback, typval_T *argv) +{ + typval_T rettv; + + if (safe_to_invoke_callback == 0) + iemsg("INTERNAL: Invoking callback when it is not safe"); + + argv[0].v_type = VAR_CHANNEL; + argv[0].vval.v_channel = channel; + + call_callback(callback, -1, &rettv, 2, argv); + clear_tv(&rettv); + channel_need_redraw = TRUE; +} + +/* + * Return the first node from "channel"/"part" without removing it. + * Returns NULL if there is nothing. + */ + readq_T * +channel_peek(channel_T *channel, ch_part_T part) +{ + readq_T *head = &channel->ch_part[part].ch_head; + + return head->rq_next; +} + +/* + * Return a pointer to the first NL in "node". + * Skips over NUL characters. + * Returns NULL if there is no NL. + */ + char_u * +channel_first_nl(readq_T *node) +{ + char_u *buffer = node->rq_buffer; + long_u i; + + for (i = 0; i < node->rq_buflen; ++i) + if (buffer[i] == NL) + return buffer + i; + return NULL; +} + +/* + * Return the first buffer from channel "channel"/"part" and remove it. + * The caller must free it. + * Returns NULL if there is nothing. + */ + char_u * +channel_get(channel_T *channel, ch_part_T part, int *outlen) +{ + readq_T *head = &channel->ch_part[part].ch_head; + readq_T *node = head->rq_next; + char_u *p; + + if (node == NULL) + return NULL; + if (outlen != NULL) + *outlen += node->rq_buflen; + // dispose of the node but keep the buffer + p = node->rq_buffer; + head->rq_next = node->rq_next; + if (node->rq_next == NULL) + head->rq_prev = NULL; + else + node->rq_next->rq_prev = NULL; + vim_free(node); + return p; +} + +/* + * Returns the whole buffer contents concatenated for "channel"/"part". + * Replaces NUL bytes with NL. + */ + static char_u * +channel_get_all(channel_T *channel, ch_part_T part, int *outlen) +{ + readq_T *head = &channel->ch_part[part].ch_head; + readq_T *node; + long_u len = 0; + char_u *res; + char_u *p; + + // Concatenate everything into one buffer. + for (node = head->rq_next; node != NULL; node = node->rq_next) + len += node->rq_buflen; + res = alloc(len + 1); + if (res == NULL) + return NULL; + p = res; + for (node = head->rq_next; node != NULL; node = node->rq_next) + { + mch_memmove(p, node->rq_buffer, node->rq_buflen); + p += node->rq_buflen; + } + *p = NUL; + + // Free all buffers + do + { + p = channel_get(channel, part, NULL); + vim_free(p); + } while (p != NULL); + + if (outlen != NULL) + { + // Returning the length, keep NUL characters. + *outlen += len; + return res; + } + + // Turn all NUL into NL, so that the result can be used as a string. + p = res; + while (p < res + len) + { + if (*p == NUL) + *p = NL; +#ifdef MSWIN + else if (*p == 0x1b) + { + // crush the escape sequence OSC 0/1/2: ESC ]0; + if (p + 3 < res + len + && p[1] == ']' + && (p[2] == '0' || p[2] == '1' || p[2] == '2') + && p[3] == ';') + { + // '\a' becomes a NL + while (p < res + (len - 1) && *p != '\a') + ++p; + // BEL is zero width characters, suppress display mistake + // ConPTY (after 10.0.18317) requires advance checking + if (p[-1] == NUL) + p[-1] = 0x07; + } + } +#endif + ++p; + } + + return res; +} + +/* + * Consume "len" bytes from the head of "node". + * Caller must check these bytes are available. + */ + void +channel_consume(channel_T *channel, ch_part_T part, int len) +{ + readq_T *head = &channel->ch_part[part].ch_head; + readq_T *node = head->rq_next; + char_u *buf = node->rq_buffer; + + mch_memmove(buf, buf + len, node->rq_buflen - len); + node->rq_buflen -= len; + node->rq_buffer[node->rq_buflen] = NUL; +} + +/* + * Collapses the first and second buffer for "channel"/"part". + * Returns FAIL if nothing was done. + * When "want_nl" is TRUE collapse more buffers until a NL is found. + * When the channel part mode is "lsp", collapse all the buffers as the http + * header and the JSON content can be present in multiple buffers. + */ + int +channel_collapse(channel_T *channel, ch_part_T part, int want_nl) +{ + ch_mode_T mode = channel->ch_part[part].ch_mode; + readq_T *head = &channel->ch_part[part].ch_head; + readq_T *node = head->rq_next; + readq_T *last_node; + readq_T *n; + char_u *newbuf; + char_u *p; + long_u len; + + if (node == NULL || node->rq_next == NULL) + return FAIL; + + last_node = node->rq_next; + len = node->rq_buflen + last_node->rq_buflen; + if (want_nl || mode == CH_MODE_LSP) + while (last_node->rq_next != NULL + && (mode == CH_MODE_LSP + || channel_first_nl(last_node) == NULL)) + { + last_node = last_node->rq_next; + len += last_node->rq_buflen; + } + + p = newbuf = alloc(len + 1); + if (newbuf == NULL) + return FAIL; // out of memory + mch_memmove(p, node->rq_buffer, node->rq_buflen); + p += node->rq_buflen; + vim_free(node->rq_buffer); + node->rq_buffer = newbuf; + for (n = node; n != last_node; ) + { + n = n->rq_next; + mch_memmove(p, n->rq_buffer, n->rq_buflen); + p += n->rq_buflen; + vim_free(n->rq_buffer); + } + *p = NUL; + node->rq_buflen = (long_u)(p - newbuf); + + // dispose of the collapsed nodes and their buffers + for (n = node->rq_next; n != last_node; ) + { + n = n->rq_next; + vim_free(n->rq_prev); + } + node->rq_next = last_node->rq_next; + if (last_node->rq_next == NULL) + head->rq_prev = node; + else + last_node->rq_next->rq_prev = node; + vim_free(last_node); + return OK; +} + +/* + * Store "buf[len]" on "channel"/"part". + * When "prepend" is TRUE put in front, otherwise append at the end. + * Returns OK or FAIL. + */ + static int +channel_save(channel_T *channel, ch_part_T part, char_u *buf, int len, + int prepend, char *lead) +{ + readq_T *node; + readq_T *head = &channel->ch_part[part].ch_head; + char_u *p; + int i; + + node = ALLOC_ONE(readq_T); + if (node == NULL) + return FAIL; // out of memory + // A NUL is added at the end, because netbeans code expects that. + // Otherwise a NUL may appear inside the text. + node->rq_buffer = alloc(len + 1); + if (node->rq_buffer == NULL) + { + vim_free(node); + return FAIL; // out of memory + } + + if (channel->ch_part[part].ch_mode == CH_MODE_NL) + { + // Drop any CR before a NL. + p = node->rq_buffer; + for (i = 0; i < len; ++i) + if (buf[i] != CAR || i + 1 >= len || buf[i + 1] != NL) + *p++ = buf[i]; + *p = NUL; + node->rq_buflen = (long_u)(p - node->rq_buffer); + } + else + { + mch_memmove(node->rq_buffer, buf, len); + node->rq_buffer[len] = NUL; + node->rq_buflen = (long_u)len; + } + + if (prepend) + { + // prepend node to the head of the queue + node->rq_next = head->rq_next; + node->rq_prev = NULL; + if (head->rq_next == NULL) + head->rq_prev = node; + else + head->rq_next->rq_prev = node; + head->rq_next = node; + } + else + { + // append node to the tail of the queue + node->rq_next = NULL; + node->rq_prev = head->rq_prev; + if (head->rq_prev == NULL) + head->rq_next = node; + else + head->rq_prev->rq_next = node; + head->rq_prev = node; + } + + if (ch_log_active() && lead != NULL) + ch_log_literal(lead, channel, part, buf, len); + + return OK; +} + +/* + * Try to fill the buffer of "reader". + * Returns FALSE when nothing was added. + */ + static int +channel_fill(js_read_T *reader) +{ + channel_T *channel = (channel_T *)reader->js_cookie; + ch_part_T part = reader->js_cookie_arg; + char_u *next = channel_get(channel, part, NULL); + int keeplen; + int addlen; + char_u *p; + + if (next == NULL) + return FALSE; + + keeplen = reader->js_end - reader->js_buf; + if (keeplen > 0) + { + // Prepend unused text. + addlen = (int)STRLEN(next); + p = alloc(keeplen + addlen + 1); + if (p == NULL) + { + vim_free(next); + return FALSE; + } + mch_memmove(p, reader->js_buf, keeplen); + mch_memmove(p + keeplen, next, addlen + 1); + vim_free(next); + next = p; + } + + vim_free(reader->js_buf); + reader->js_buf = next; + return TRUE; +} + +/* + * Process the HTTP header in a Language Server Protocol (LSP) message. + * + * The message format is described in the LSP specification: + * https://microsoft.github.io/language-server-protocol/specification + * + * It has the following two fields: + * + * Content-Length: ... + * Content-Type: application/vscode-jsonrpc; charset=utf-8 + * + * Each field ends with "\r\n". The header ends with an additional "\r\n". + * + * Returns OK if a valid header is received and FAIL if some fields in the + * header are not correct. Returns MAYBE if a partial header is received and + * need to wait for more data to arrive. + */ + static int +channel_process_lsp_http_hdr(js_read_T *reader) +{ + char_u *line_start; + char_u *p; + int_u hdr_len; + int payload_len = -1; + int_u jsbuf_len; + + // We find the end once, to avoid calling strlen() many times. + jsbuf_len = (int_u)STRLEN(reader->js_buf); + reader->js_end = reader->js_buf + jsbuf_len; + + p = reader->js_buf; + + // Process each line in the header till an empty line is read (header + // separator). + while (TRUE) + { + line_start = p; + while (*p != NUL && *p != '\n') + p++; + if (*p == NUL) // partial header + return MAYBE; + p++; + + // process the content length field (if present) + if ((p - line_start > 16) + && STRNICMP(line_start, "Content-Length: ", 16) == 0) + { + errno = 0; + payload_len = strtol((char *)line_start + 16, NULL, 10); + if (errno == ERANGE || payload_len < 0) + // invalid length, discard the payload + return FAIL; + } + + if ((p - line_start) == 2 && line_start[0] == '\r' && + line_start[1] == '\n') + // reached the empty line + break; + } + + if (payload_len == -1) + // Content-Length field is not present in the header + return FAIL; + + hdr_len = p - reader->js_buf; + + // if the entire payload is not received, wait for more data to arrive + if (jsbuf_len < hdr_len + payload_len) + return MAYBE; + + reader->js_used += hdr_len; + // recalculate the end based on the length read from the header. + reader->js_end = reader->js_buf + hdr_len + payload_len; + + return OK; +} + +/* + * Use the read buffer of "channel"/"part" and parse a JSON message that is + * complete. The messages are added to the queue. + * Return TRUE if there is more to read. + */ + static int +channel_parse_json(channel_T *channel, ch_part_T part) +{ + js_read_T reader; + typval_T listtv; + jsonq_T *item; + chanpart_T *chanpart = &channel->ch_part[part]; + jsonq_T *head = &chanpart->ch_json_head; + int status = OK; + int ret; + + if (channel_peek(channel, part) == NULL) + return FALSE; + + reader.js_buf = channel_get(channel, part, NULL); + reader.js_used = 0; + reader.js_fill = channel_fill; + reader.js_cookie = channel; + reader.js_cookie_arg = part; + + if (chanpart->ch_mode == CH_MODE_LSP) + status = channel_process_lsp_http_hdr(&reader); + + // When a message is incomplete we wait for a short while for more to + // arrive. After the delay drop the input, otherwise a truncated string + // or list will make us hang. + // Do not generate error messages, they will be written in a channel log. + if (status == OK) + { + ++emsg_silent; + status = json_decode(&reader, &listtv, + chanpart->ch_mode == CH_MODE_JS ? JSON_JS : 0); + --emsg_silent; + } + if (status == OK) + { + // Only accept the response when it is a list with at least two + // items. + if (chanpart->ch_mode == CH_MODE_LSP && listtv.v_type != VAR_DICT) + { + ch_error(channel, "Did not receive a LSP dict, discarding"); + clear_tv(&listtv); + } + else if (chanpart->ch_mode != CH_MODE_LSP + && (listtv.v_type != VAR_LIST || listtv.vval.v_list->lv_len < 2)) + { + if (listtv.v_type != VAR_LIST) + ch_error(channel, "Did not receive a list, discarding"); + else + ch_error(channel, "Expected list with two items, got %d", + listtv.vval.v_list->lv_len); + clear_tv(&listtv); + } + else + { + item = ALLOC_ONE(jsonq_T); + if (item == NULL) + clear_tv(&listtv); + else + { + item->jq_no_callback = FALSE; + item->jq_value = alloc_tv(); + if (item->jq_value == NULL) + { + vim_free(item); + clear_tv(&listtv); + } + else + { + *item->jq_value = listtv; + item->jq_prev = head->jq_prev; + head->jq_prev = item; + item->jq_next = NULL; + if (item->jq_prev == NULL) + head->jq_next = item; + else + item->jq_prev->jq_next = item; + } + } + } + } + + if (status == OK) + chanpart->ch_wait_len = 0; + else if (status == MAYBE) + { + size_t buflen = STRLEN(reader.js_buf); + + if (chanpart->ch_wait_len < buflen) + { + // First time encountering incomplete message or after receiving + // more (but still incomplete): set a deadline of 100 msec. + ch_log(channel, + "Incomplete message (%d bytes) - wait 100 msec for more", + (int)buflen); + reader.js_used = 0; + chanpart->ch_wait_len = buflen; +#ifdef MSWIN + chanpart->ch_deadline = GetTickCount() + 100L; +#else + gettimeofday(&chanpart->ch_deadline, NULL); + chanpart->ch_deadline.tv_usec += 100 * 1000; + if (chanpart->ch_deadline.tv_usec > 1000 * 1000) + { + chanpart->ch_deadline.tv_usec -= 1000 * 1000; + ++chanpart->ch_deadline.tv_sec; + } +#endif + } + else + { + int timeout; +#ifdef MSWIN + timeout = GetTickCount() > chanpart->ch_deadline; +#else + { + struct timeval now_tv; + + gettimeofday(&now_tv, NULL); + timeout = now_tv.tv_sec > chanpart->ch_deadline.tv_sec + || (now_tv.tv_sec == chanpart->ch_deadline.tv_sec + && now_tv.tv_usec > chanpart->ch_deadline.tv_usec); + } +#endif + if (timeout) + { + status = FAIL; + chanpart->ch_wait_len = 0; + ch_log(channel, "timed out"); + } + else + { + reader.js_used = 0; + ch_log(channel, "still waiting on incomplete message"); + } + } + } + + if (status == FAIL) + { + ch_error(channel, "Decoding failed - discarding input"); + ret = FALSE; + chanpart->ch_wait_len = 0; + } + else if (reader.js_buf[reader.js_used] != NUL) + { + // Put the unread part back into the channel. + channel_save(channel, part, reader.js_buf + reader.js_used, + (int)(reader.js_end - reader.js_buf) - reader.js_used, + TRUE, NULL); + ret = status == MAYBE ? FALSE: TRUE; + } + else + ret = FALSE; + + vim_free(reader.js_buf); + return ret; +} + +/* + * Remove "node" from the queue that it is in. Does not free it. + */ + static void +remove_cb_node(cbq_T *head, cbq_T *node) +{ + if (node->cq_prev == NULL) + head->cq_next = node->cq_next; + else + node->cq_prev->cq_next = node->cq_next; + if (node->cq_next == NULL) + head->cq_prev = node->cq_prev; + else + node->cq_next->cq_prev = node->cq_prev; +} + +/* + * Remove "node" from the queue that it is in and free it. + * Caller should have freed or used node->jq_value. + */ + static void +remove_json_node(jsonq_T *head, jsonq_T *node) +{ + if (node->jq_prev == NULL) + head->jq_next = node->jq_next; + else + node->jq_prev->jq_next = node->jq_next; + if (node->jq_next == NULL) + head->jq_prev = node->jq_prev; + else + node->jq_next->jq_prev = node->jq_prev; + vim_free(node); +} + +/* + * Add "id" to the list of JSON message IDs we are waiting on. + */ + static void +channel_add_block_id(chanpart_T *chanpart, int id) +{ + garray_T *gap = &chanpart->ch_block_ids; + + if (gap->ga_growsize == 0) + ga_init2(gap, sizeof(int), 10); + if (ga_grow(gap, 1) == OK) + { + ((int *)gap->ga_data)[gap->ga_len] = id; + ++gap->ga_len; + } +} + +/* + * Remove "id" from the list of JSON message IDs we are waiting on. + */ + static void +channel_remove_block_id(chanpart_T *chanpart, int id) +{ + garray_T *gap = &chanpart->ch_block_ids; + int i; + + for (i = 0; i < gap->ga_len; ++i) + if (((int *)gap->ga_data)[i] == id) + { + --gap->ga_len; + if (i < gap->ga_len) + { + int *p = ((int *)gap->ga_data) + i; + + mch_memmove(p, p + 1, (gap->ga_len - i) * sizeof(int)); + } + return; + } + siemsg("INTERNAL: channel_remove_block_id: cannot find id %d", id); +} + +/* + * Return TRUE if "id" is in the list of JSON message IDs we are waiting on. + */ + static int +channel_has_block_id(chanpart_T *chanpart, int id) +{ + garray_T *gap = &chanpart->ch_block_ids; + int i; + + for (i = 0; i < gap->ga_len; ++i) + if (((int *)gap->ga_data)[i] == id) + return TRUE; + return FALSE; +} + +/* + * Get a message from the JSON queue for channel "channel". + * When "id" is positive it must match the first number in the list. + * When "id" is zero or negative jut get the first message. But not one + * in the ch_block_ids list. + * When "without_callback" is TRUE also get messages that were pushed back. + * Return OK when found and return the value in "rettv". + * Return FAIL otherwise. + */ + static int +channel_get_json( + channel_T *channel, + ch_part_T part, + int id, + int without_callback, + typval_T **rettv) +{ + jsonq_T *head = &channel->ch_part[part].ch_json_head; + jsonq_T *item = head->jq_next; + + while (item != NULL) + { + list_T *l; + typval_T *tv; + + if (channel->ch_part[part].ch_mode != CH_MODE_LSP) + { + l = item->jq_value->vval.v_list; + CHECK_LIST_MATERIALIZE(l); + tv = &l->lv_first->li_tv; + } + else + { + dict_T *d; + dictitem_T *di; + + // LSP message payload is a JSON-RPC dict. + // For RPC requests and responses, the 'id' item will be present. + // For notifications, it will not be present. + if (id > 0) + { + if (item->jq_value->v_type != VAR_DICT) + goto nextitem; + d = item->jq_value->vval.v_dict; + if (d == NULL) + goto nextitem; + di = dict_find(d, (char_u *)"id", -1); + if (di == NULL) + goto nextitem; + tv = &di->di_tv; + } + else + tv = item->jq_value; + } + + if ((without_callback || !item->jq_no_callback) + && ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id) + || (id <= 0 && (tv->v_type != VAR_NUMBER + || tv->vval.v_number == 0 + || !channel_has_block_id( + &channel->ch_part[part], tv->vval.v_number))))) + { + *rettv = item->jq_value; + if (tv->v_type == VAR_NUMBER) + ch_log(channel, "Getting JSON message %ld", + (long)tv->vval.v_number); + remove_json_node(head, item); + return OK; + } +nextitem: + item = item->jq_next; + } + return FAIL; +} + +/* + * Put back "rettv" into the JSON queue, there was no callback for it. + * Takes over the values in "rettv". + */ + static void +channel_push_json(channel_T *channel, ch_part_T part, typval_T *rettv) +{ + jsonq_T *head = &channel->ch_part[part].ch_json_head; + jsonq_T *item = head->jq_next; + jsonq_T *newitem; + + if (head->jq_prev != NULL && head->jq_prev->jq_no_callback) + // last item was pushed back, append to the end + item = NULL; + else while (item != NULL && item->jq_no_callback) + // append after the last item that was pushed back + item = item->jq_next; + + newitem = ALLOC_ONE(jsonq_T); + if (newitem == NULL) + { + clear_tv(rettv); + return; + } + + newitem->jq_value = alloc_tv(); + if (newitem->jq_value == NULL) + { + vim_free(newitem); + clear_tv(rettv); + return; + } + + newitem->jq_no_callback = FALSE; + *newitem->jq_value = *rettv; + if (item == NULL) + { + // append to the end + newitem->jq_prev = head->jq_prev; + head->jq_prev = newitem; + newitem->jq_next = NULL; + if (newitem->jq_prev == NULL) + head->jq_next = newitem; + else + newitem->jq_prev->jq_next = newitem; + } + else + { + // append after "item" + newitem->jq_prev = item; + newitem->jq_next = item->jq_next; + item->jq_next = newitem; + if (newitem->jq_next == NULL) + head->jq_prev = newitem; + else + newitem->jq_next->jq_prev = newitem; + } +} + +#define CH_JSON_MAX_ARGS 4 + +/* + * Execute a command received over "channel"/"part" + * "argv[0]" is the command string. + * "argv[1]" etc. have further arguments, type is VAR_UNKNOWN if missing. + */ + static void +channel_exe_cmd(channel_T *channel, ch_part_T part, typval_T *argv) +{ + char_u *cmd = argv[0].vval.v_string; + char_u *arg; + int options = channel->ch_part[part].ch_mode == CH_MODE_JS + ? JSON_JS : 0; + + if (argv[1].v_type != VAR_STRING) + { + ch_error(channel, "received command with non-string argument"); + if (p_verbose > 2) + emsg(_(e_received_command_with_non_string_argument)); + return; + } + arg = argv[1].vval.v_string; + if (arg == NULL) + arg = (char_u *)""; + + if (STRCMP(cmd, "ex") == 0) + { + int called_emsg_before = called_emsg; + char_u *p = arg; + int do_emsg_silent; + + ch_log(channel, "Executing ex command '%s'", (char *)arg); + do_emsg_silent = !checkforcmd(&p, "echoerr", 5); + if (do_emsg_silent) + ++emsg_silent; + do_cmdline_cmd(arg); + if (do_emsg_silent) + --emsg_silent; + if (called_emsg > called_emsg_before) + ch_log(channel, "Ex command error: '%s'", + (char *)get_vim_var_str(VV_ERRMSG)); + } + else if (STRCMP(cmd, "normal") == 0) + { + exarg_T ea; + + ch_log(channel, "Executing normal command '%s'", (char *)arg); + CLEAR_FIELD(ea); + ea.arg = arg; + ea.addr_count = 0; + ea.forceit = TRUE; // no mapping + ex_normal(&ea); + } + else if (STRCMP(cmd, "redraw") == 0) + { + ch_log(channel, "redraw"); + redraw_cmd(*arg != NUL); + showruler(FALSE); + setcursor(); + out_flush_cursor(TRUE, FALSE); + } + else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "call") == 0) + { + int is_call = cmd[0] == 'c'; + int id_idx = is_call ? 3 : 2; + + if (argv[id_idx].v_type != VAR_UNKNOWN + && argv[id_idx].v_type != VAR_NUMBER) + { + ch_error(channel, "last argument for expr/call must be a number"); + if (p_verbose > 2) + emsg(_(e_last_argument_for_expr_call_must_be_number)); + } + else if (is_call && argv[2].v_type != VAR_LIST) + { + ch_error(channel, "third argument for call must be a list"); + if (p_verbose > 2) + emsg(_(e_third_argument_for_call_must_be_list)); + } + else + { + typval_T *tv = NULL; + typval_T res_tv; + typval_T err_tv; + char_u *json = NULL; + + // Don't pollute the display with errors. + // Do generate the errors so that try/catch works. + ++emsg_silent; + if (!is_call) + { + ch_log(channel, "Evaluating expression '%s'", (char *)arg); + tv = eval_expr(arg, NULL); + } + else + { + ch_log(channel, "Calling '%s'", (char *)arg); + if (func_call(arg, &argv[2], NULL, NULL, &res_tv) == OK) + tv = &res_tv; + } + + if (argv[id_idx].v_type == VAR_NUMBER) + { + int id = argv[id_idx].vval.v_number; + + if (tv != NULL) + json = json_encode_nr_expr(id, tv, options | JSON_NL); + if (tv == NULL || (json != NULL && *json == NUL)) + { + // If evaluation failed or the result can't be encoded + // then return the string "ERROR". + vim_free(json); + err_tv.v_type = VAR_STRING; + err_tv.vval.v_string = (char_u *)"ERROR"; + json = json_encode_nr_expr(id, &err_tv, options | JSON_NL); + } + if (json != NULL) + { + channel_send(channel, + part == PART_SOCK ? PART_SOCK : PART_IN, + json, (int)STRLEN(json), (char *)cmd); + vim_free(json); + } + } + --emsg_silent; + if (tv == &res_tv) + clear_tv(tv); + else + free_tv(tv); + } + } + else if (p_verbose > 2) + { + ch_error(channel, "Received unknown command: %s", (char *)cmd); + semsg(_(e_received_unknown_command_str), cmd); + } +} + +/* + * Invoke the callback at "cbhead". + * Does not redraw but sets channel_need_redraw. + */ + static void +invoke_one_time_callback( + channel_T *channel, + cbq_T *cbhead, + cbq_T *item, + typval_T *argv) +{ + ch_log(channel, "Invoking one-time callback %s", + (char *)item->cq_callback.cb_name); + // Remove the item from the list first, if the callback + // invokes ch_close() the list will be cleared. + remove_cb_node(cbhead, item); + invoke_callback(channel, &item->cq_callback, argv); + free_callback(&item->cq_callback); + vim_free(item); +} + + static void +append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part) +{ + aco_save_T aco; + linenr_T lnum = buffer->b_ml.ml_line_count; + int save_write_to = buffer->b_write_to_channel; + chanpart_T *ch_part = &channel->ch_part[part]; + int save_p_ma = buffer->b_p_ma; + int empty = (buffer->b_ml.ml_flags & ML_EMPTY) ? 1 : 0; + + if (!buffer->b_p_ma && !ch_part->ch_nomodifiable) + { + if (!ch_part->ch_nomod_error) + { + ch_error(channel, "Buffer is not modifiable, cannot append"); + ch_part->ch_nomod_error = TRUE; + } + return; + } + + // If the buffer is also used as input insert above the last + // line. Don't write these lines. + if (save_write_to) + { + --lnum; + buffer->b_write_to_channel = FALSE; + } + + // Append to the buffer + ch_log(channel, "appending line %d to buffer %s", + (int)lnum + 1 - empty, buffer->b_fname); + + buffer->b_p_ma = TRUE; + + // Set curbuf to "buffer", temporarily. + aucmd_prepbuf(&aco, buffer); + if (curbuf != buffer) + { + // Could not find a window for this buffer, the following might cause + // trouble, better bail out. + return; + } + + u_sync(TRUE); + // ignore undo failure, undo is not very useful here + vim_ignored = u_save(lnum - empty, lnum + 1); + + if (empty) + { + // The buffer is empty, replace the first (dummy) line. + ml_replace(lnum, msg, TRUE); + lnum = 0; + } + else + ml_append(lnum, msg, 0, FALSE); + appended_lines_mark(lnum, 1L); + + // reset notion of buffer + aucmd_restbuf(&aco); + + if (ch_part->ch_nomodifiable) + buffer->b_p_ma = FALSE; + else + buffer->b_p_ma = save_p_ma; + + if (buffer->b_nwindows > 0) + { + win_T *wp; + + FOR_ALL_WINDOWS(wp) + { + if (wp->w_buffer == buffer) + { + int move_cursor = save_write_to + ? wp->w_cursor.lnum == lnum + 1 + : (wp->w_cursor.lnum == lnum + && wp->w_cursor.col == 0); + + // If the cursor is at or above the new line, move it one line + // down. If the topline is outdated update it now. + if (move_cursor || wp->w_topline > buffer->b_ml.ml_line_count) + { + win_T *save_curwin = curwin; + + if (move_cursor) + ++wp->w_cursor.lnum; + curwin = wp; + curbuf = curwin->w_buffer; + scroll_cursor_bot(0, FALSE); + curwin = save_curwin; + curbuf = curwin->w_buffer; + } + } + } + redraw_buf_and_status_later(buffer, UPD_VALID); + channel_need_redraw = TRUE; + } + + if (save_write_to) + { + channel_T *ch; + + // Find channels reading from this buffer and adjust their + // next-to-read line number. + buffer->b_write_to_channel = TRUE; + FOR_ALL_CHANNELS(ch) + { + chanpart_T *in_part = &ch->ch_part[PART_IN]; + + if (in_part->ch_bufref.br_buf == buffer) + in_part->ch_buf_bot = buffer->b_ml.ml_line_count; + } + } +} + + static void +drop_messages(channel_T *channel, ch_part_T part) +{ + char_u *msg; + + while ((msg = channel_get(channel, part, NULL)) != NULL) + { + ch_log(channel, "Dropping message '%s'", (char *)msg); + vim_free(msg); + } +} + +/* + * Return TRUE if for "channel" / "part" ch_json_head should be used. + */ + static int +channel_use_json_head(channel_T *channel, ch_part_T part) +{ + ch_mode_T ch_mode = channel->ch_part[part].ch_mode; + + return ch_mode == CH_MODE_JSON || ch_mode == CH_MODE_JS + || ch_mode == CH_MODE_LSP; +} + +/* + * Invoke a callback for "channel"/"part" if needed. + * This does not redraw but sets channel_need_redraw when redraw is needed. + * Return TRUE when a message was handled, there might be another one. + */ + static int +may_invoke_callback(channel_T *channel, ch_part_T part) +{ + char_u *msg = NULL; + typval_T *listtv = NULL; + typval_T argv[CH_JSON_MAX_ARGS]; + int seq_nr = -1; + chanpart_T *ch_part = &channel->ch_part[part]; + ch_mode_T ch_mode = ch_part->ch_mode; + cbq_T *cbhead = &ch_part->ch_cb_head; + cbq_T *cbitem; + callback_T *callback = NULL; + buf_T *buffer = NULL; + char_u *p; + int called_otc; // one time callbackup + + if (channel->ch_nb_close_cb != NULL) + // this channel is handled elsewhere (netbeans) + return FALSE; + + // Use a message-specific callback, part callback or channel callback + for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next) + if (cbitem->cq_seq_nr == 0) + break; + if (cbitem != NULL) + callback = &cbitem->cq_callback; + else if (ch_part->ch_callback.cb_name != NULL) + callback = &ch_part->ch_callback; + else if (channel->ch_callback.cb_name != NULL) + callback = &channel->ch_callback; + + buffer = ch_part->ch_bufref.br_buf; + if (buffer != NULL && (!bufref_valid(&ch_part->ch_bufref) + || buffer->b_ml.ml_mfp == NULL)) + { + // buffer was wiped out or unloaded + ch_log(channel, "%s buffer has been wiped out", ch_part_names[part]); + ch_part->ch_bufref.br_buf = NULL; + buffer = NULL; + } + + if (channel_use_json_head(channel, part)) + { + listitem_T *item; + int argc = 0; + + // Get any json message in the queue. + if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL) + { + if (ch_mode == CH_MODE_LSP) + // In the "lsp" mode, the http header and the json payload may + // be received in multiple messages. So concatenate all the + // received messages. + (void)channel_collapse(channel, part, FALSE); + + // Parse readahead, return when there is still no message. + channel_parse_json(channel, part); + if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL) + return FALSE; + } + + if (ch_mode == CH_MODE_LSP) + { + dict_T *d = listtv->vval.v_dict; + dictitem_T *di; + + seq_nr = 0; + if (d != NULL) + { + di = dict_find(d, (char_u *)"id", -1); + if (di != NULL && di->di_tv.v_type == VAR_NUMBER) + seq_nr = di->di_tv.vval.v_number; + } + + argv[1] = *listtv; + } + else + { + for (item = listtv->vval.v_list->lv_first; + item != NULL && argc < CH_JSON_MAX_ARGS; + item = item->li_next) + argv[argc++] = item->li_tv; + while (argc < CH_JSON_MAX_ARGS) + argv[argc++].v_type = VAR_UNKNOWN; + + if (argv[0].v_type == VAR_STRING) + { + // ["cmd", arg] or ["cmd", arg, arg] or ["cmd", arg, arg, arg] + channel_exe_cmd(channel, part, argv); + free_tv(listtv); + return TRUE; + } + + if (argv[0].v_type != VAR_NUMBER) + { + ch_error(channel, + "Dropping message with invalid sequence number type"); + free_tv(listtv); + return FALSE; + } + seq_nr = argv[0].vval.v_number; + } + } + else if (channel_peek(channel, part) == NULL) + { + // nothing to read on RAW or NL channel + return FALSE; + } + else + { + // If there is no callback or buffer drop the message. + if (callback == NULL && buffer == NULL) + { + // If there is a close callback it may use ch_read() to get the + // messages. + if (channel->ch_close_cb.cb_name == NULL && !channel->ch_drop_never) + drop_messages(channel, part); + return FALSE; + } + + if (ch_mode == CH_MODE_NL) + { + char_u *nl = NULL; + char_u *buf; + readq_T *node; + + // See if we have a message ending in NL in the first buffer. If + // not try to concatenate the first and the second buffer. + while (TRUE) + { + node = channel_peek(channel, part); + nl = channel_first_nl(node); + if (nl != NULL) + break; + if (channel_collapse(channel, part, TRUE) == FAIL) + { + if (ch_part->ch_fd == INVALID_FD && node->rq_buflen > 0) + break; + return FALSE; // incomplete message + } + } + buf = node->rq_buffer; + + // Convert NUL to NL, the internal representation. + for (p = buf; (nl == NULL || p < nl) + && p < buf + node->rq_buflen; ++p) + if (*p == NUL) + *p = NL; + + if (nl == NULL) + { + // get the whole buffer, drop the NL + msg = channel_get(channel, part, NULL); + } + else if (nl + 1 == buf + node->rq_buflen) + { + // get the whole buffer + msg = channel_get(channel, part, NULL); + *nl = NUL; + } + else + { + // Copy the message into allocated memory (excluding the NL) + // and remove it from the buffer (including the NL). + msg = vim_strnsave(buf, nl - buf); + channel_consume(channel, part, (int)(nl - buf) + 1); + } + } + else + { + // For a raw channel we don't know where the message ends, just + // get everything we have. + // Convert NUL to NL, the internal representation. + msg = channel_get_all(channel, part, NULL); + } + + if (msg == NULL) + return FALSE; // out of memory (and avoids Coverity warning) + + argv[1].v_type = VAR_STRING; + argv[1].vval.v_string = msg; + } + + called_otc = FALSE; + if (seq_nr > 0) + { + // JSON or JS or LSP mode: invoke the one-time callback with the + // matching nr + for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next) + if (cbitem->cq_seq_nr == seq_nr) + { + invoke_one_time_callback(channel, cbhead, cbitem, argv); + called_otc = TRUE; + break; + } + } + + if (seq_nr > 0 && (ch_mode != CH_MODE_LSP || called_otc)) + { + if (!called_otc) + { + // If the 'drop' channel attribute is set to 'never' or if + // ch_evalexpr() is waiting for this response message, then don't + // drop this message. + if (channel->ch_drop_never) + { + // message must be read with ch_read() + channel_push_json(channel, part, listtv); + + // Change the type to avoid the value being freed. + listtv->v_type = VAR_NUMBER; + free_tv(listtv); + listtv = NULL; + } + else + ch_log(channel, "Dropping message %d without callback", + seq_nr); + } + } + else if (callback != NULL || buffer != NULL) + { + if (buffer != NULL) + { + if (msg == NULL) + // JSON or JS mode: re-encode the message. + msg = json_encode(listtv, ch_mode); + if (msg != NULL) + { +#ifdef FEAT_TERMINAL + if (buffer->b_term != NULL) + write_to_term(buffer, msg, channel); + else +#endif + append_to_buffer(buffer, msg, channel, part); + } + } + + if (callback != NULL) + { + if (cbitem != NULL) + invoke_one_time_callback(channel, cbhead, cbitem, argv); + else + { + // invoke the channel callback + ch_log(channel, "Invoking channel callback %s", + (char *)callback->cb_name); + invoke_callback(channel, callback, argv); + } + } + } + else + ch_log(channel, "Dropping message %d", seq_nr); + + if (listtv != NULL) + free_tv(listtv); + vim_free(msg); + + return TRUE; +} + +#if defined(FEAT_NETBEANS_INTG) || defined(PROTO) +/* + * Return TRUE when channel "channel" is open for writing to. + * Also returns FALSE or invalid "channel". + */ + int +channel_can_write_to(channel_T *channel) +{ + return channel != NULL && (channel->CH_SOCK_FD != INVALID_FD + || channel->CH_IN_FD != INVALID_FD); +} +#endif + +/* + * Return TRUE when channel "channel" is open for reading or writing. + * Also returns FALSE for invalid "channel". + */ + int +channel_is_open(channel_T *channel) +{ + return channel != NULL && (channel->CH_SOCK_FD != INVALID_FD + || channel->CH_IN_FD != INVALID_FD + || channel->CH_OUT_FD != INVALID_FD + || channel->CH_ERR_FD != INVALID_FD); +} + +/* + * Return a pointer indicating the readahead. Can only be compared between + * calls. Returns NULL if there is no readahead. + */ + static void * +channel_readahead_pointer(channel_T *channel, ch_part_T part) +{ + if (channel_use_json_head(channel, part)) + { + jsonq_T *head = &channel->ch_part[part].ch_json_head; + + if (head->jq_next == NULL) + // Parse json from readahead, there might be a complete message to + // process. + channel_parse_json(channel, part); + + return head->jq_next; + } + return channel_peek(channel, part); +} + +/* + * Return TRUE if "channel" has JSON or other typeahead. + */ + static int +channel_has_readahead(channel_T *channel, ch_part_T part) +{ + return channel_readahead_pointer(channel, part) != NULL; +} + +/* + * Return a string indicating the status of the channel. + * If "req_part" is not negative check that part. + */ + static char * +channel_status(channel_T *channel, int req_part) +{ + ch_part_T part; + int has_readahead = FALSE; + + if (channel == NULL) + return "fail"; + if (req_part == PART_OUT) + { + if (channel->CH_OUT_FD != INVALID_FD) + return "open"; + if (channel_has_readahead(channel, PART_OUT)) + has_readahead = TRUE; + } + else if (req_part == PART_ERR) + { + if (channel->CH_ERR_FD != INVALID_FD) + return "open"; + if (channel_has_readahead(channel, PART_ERR)) + has_readahead = TRUE; + } + else + { + if (channel_is_open(channel)) + return "open"; + for (part = PART_SOCK; part < PART_IN; ++part) + if (channel_has_readahead(channel, part)) + { + has_readahead = TRUE; + break; + } + } + + if (has_readahead) + return "buffered"; + return "closed"; +} + + static void +channel_part_info(channel_T *channel, dict_T *dict, char *name, ch_part_T part) +{ + chanpart_T *chanpart = &channel->ch_part[part]; + char namebuf[20]; // longest is "sock_timeout" + size_t tail; + char *status; + char *s = ""; + + vim_strncpy((char_u *)namebuf, (char_u *)name, 4); + STRCAT(namebuf, "_"); + tail = STRLEN(namebuf); + + STRCPY(namebuf + tail, "status"); + if (chanpart->ch_fd != INVALID_FD) + status = "open"; + else if (channel_has_readahead(channel, part)) + status = "buffered"; + else + status = "closed"; + dict_add_string(dict, namebuf, (char_u *)status); + + STRCPY(namebuf + tail, "mode"); + switch (chanpart->ch_mode) + { + case CH_MODE_NL: s = "NL"; break; + case CH_MODE_RAW: s = "RAW"; break; + case CH_MODE_JSON: s = "JSON"; break; + case CH_MODE_JS: s = "JS"; break; + case CH_MODE_LSP: s = "LSP"; break; + } + dict_add_string(dict, namebuf, (char_u *)s); + + STRCPY(namebuf + tail, "io"); + if (part == PART_SOCK) + s = "socket"; + else switch (chanpart->ch_io) + { + case JIO_NULL: s = "null"; break; + case JIO_PIPE: s = "pipe"; break; + case JIO_FILE: s = "file"; break; + case JIO_BUFFER: s = "buffer"; break; + case JIO_OUT: s = "out"; break; + } + dict_add_string(dict, namebuf, (char_u *)s); + + STRCPY(namebuf + tail, "timeout"); + dict_add_number(dict, namebuf, chanpart->ch_timeout); +} + + static void +channel_info(channel_T *channel, dict_T *dict) +{ + dict_add_number(dict, "id", channel->ch_id); + dict_add_string(dict, "status", (char_u *)channel_status(channel, -1)); + + if (channel->ch_hostname != NULL) + { + if (channel->ch_port) + { + dict_add_string(dict, "hostname", (char_u *)channel->ch_hostname); + dict_add_number(dict, "port", channel->ch_port); + } + else + // Unix-domain socket. + dict_add_string(dict, "path", (char_u *)channel->ch_hostname); + channel_part_info(channel, dict, "sock", PART_SOCK); + } + else + { + channel_part_info(channel, dict, "out", PART_OUT); + channel_part_info(channel, dict, "err", PART_ERR); + channel_part_info(channel, dict, "in", PART_IN); + } +} + +/* + * Close channel "channel". + * Trigger the close callback if "invoke_close_cb" is TRUE. + * Does not clear the buffers. + */ + void +channel_close(channel_T *channel, int invoke_close_cb) +{ + ch_log(channel, "Closing channel"); + +#ifdef FEAT_GUI + channel_gui_unregister(channel); +#endif + + ch_close_part(channel, PART_SOCK); + ch_close_part(channel, PART_IN); + ch_close_part(channel, PART_OUT); + ch_close_part(channel, PART_ERR); + + if (invoke_close_cb) + { + ch_part_T part; + +#ifdef FEAT_TERMINAL + // let the terminal know it is closing to avoid getting stuck + term_channel_closing(channel); +#endif + // Invoke callbacks and flush buffers before the close callback. + if (channel->ch_close_cb.cb_name != NULL) + ch_log(channel, + "Invoking callbacks and flushing buffers before closing"); + for (part = PART_SOCK; part < PART_IN; ++part) + { + if (channel->ch_close_cb.cb_name != NULL + || channel->ch_part[part].ch_bufref.br_buf != NULL) + { + // Increment the refcount to avoid the channel being freed + // halfway. + ++channel->ch_refcount; + if (channel->ch_close_cb.cb_name == NULL) + ch_log(channel, "flushing %s buffers before closing", + ch_part_names[part]); + while (may_invoke_callback(channel, part)) + ; + --channel->ch_refcount; + } + } + + if (channel->ch_close_cb.cb_name != NULL) + { + typval_T argv[1]; + typval_T rettv; + + // Increment the refcount to avoid the channel being freed + // halfway. + ++channel->ch_refcount; + ch_log(channel, "Invoking close callback %s", + (char *)channel->ch_close_cb.cb_name); + argv[0].v_type = VAR_CHANNEL; + argv[0].vval.v_channel = channel; + call_callback(&channel->ch_close_cb, -1, &rettv, 1, argv); + clear_tv(&rettv); + channel_need_redraw = TRUE; + + // the callback is only called once + free_callback(&channel->ch_close_cb); + + if (channel_need_redraw) + { + channel_need_redraw = FALSE; + redraw_after_callback(TRUE, FALSE); + } + + if (!channel->ch_drop_never) + // any remaining messages are useless now + for (part = PART_SOCK; part < PART_IN; ++part) + drop_messages(channel, part); + + --channel->ch_refcount; + } + } + + channel->ch_nb_close_cb = NULL; + +#ifdef FEAT_TERMINAL + term_channel_closed(channel); +#endif +} + +/* + * Close the "in" part channel "channel". + */ + static void +channel_close_in(channel_T *channel) +{ + ch_close_part(channel, PART_IN); +} + + static void +remove_from_writeque(writeq_T *wq, writeq_T *entry) +{ + ga_clear(&entry->wq_ga); + wq->wq_next = entry->wq_next; + if (wq->wq_next == NULL) + wq->wq_prev = NULL; + else + wq->wq_next->wq_prev = NULL; + vim_free(entry); +} + +/* + * Clear the read buffer on "channel"/"part". + */ + static void +channel_clear_one(channel_T *channel, ch_part_T part) +{ + chanpart_T *ch_part = &channel->ch_part[part]; + jsonq_T *json_head = &ch_part->ch_json_head; + cbq_T *cb_head = &ch_part->ch_cb_head; + + while (channel_peek(channel, part) != NULL) + vim_free(channel_get(channel, part, NULL)); + + while (cb_head->cq_next != NULL) + { + cbq_T *node = cb_head->cq_next; + + remove_cb_node(cb_head, node); + free_callback(&node->cq_callback); + vim_free(node); + } + + while (json_head->jq_next != NULL) + { + free_tv(json_head->jq_next->jq_value); + remove_json_node(json_head, json_head->jq_next); + } + + free_callback(&ch_part->ch_callback); + ga_clear(&ch_part->ch_block_ids); + + while (ch_part->ch_writeque.wq_next != NULL) + remove_from_writeque(&ch_part->ch_writeque, + ch_part->ch_writeque.wq_next); +} + +/* + * Clear all the read buffers on "channel". + */ + void +channel_clear(channel_T *channel) +{ + ch_log(channel, "Clearing channel"); + VIM_CLEAR(channel->ch_hostname); + channel_clear_one(channel, PART_SOCK); + channel_clear_one(channel, PART_OUT); + channel_clear_one(channel, PART_ERR); + channel_clear_one(channel, PART_IN); + free_callback(&channel->ch_callback); + free_callback(&channel->ch_close_cb); +} + +#if defined(EXITFREE) || defined(PROTO) + void +channel_free_all(void) +{ + channel_T *channel; + + ch_log(NULL, "channel_free_all()"); + FOR_ALL_CHANNELS(channel) + channel_clear(channel); +} +#endif + + +// Sent when the netbeans channel is found closed when reading. +#define DETACH_MSG_RAW "DETACH\n" + +// Buffer size for reading incoming messages. +#define MAXMSGSIZE 4096 + +/* + * Check if there are remaining data that should be written for "in_part". + */ + static int +is_channel_write_remaining(chanpart_T *in_part) +{ + buf_T *buf = in_part->ch_bufref.br_buf; + + if (in_part->ch_writeque.wq_next != NULL) + return TRUE; + if (buf == NULL) + return FALSE; + return in_part->ch_buf_append + ? (in_part->ch_buf_bot < buf->b_ml.ml_line_count) + : (in_part->ch_buf_top <= in_part->ch_buf_bot + && in_part->ch_buf_top <= buf->b_ml.ml_line_count); +} + +#if defined(HAVE_SELECT) +/* + * Add write fds where we are waiting for writing to be possible. + */ + static int +channel_fill_wfds(int maxfd_arg, fd_set *wfds) +{ + int maxfd = maxfd_arg; + channel_T *ch; + + FOR_ALL_CHANNELS(ch) + { + chanpart_T *in_part = &ch->ch_part[PART_IN]; + + if (in_part->ch_fd != INVALID_FD + && is_channel_write_remaining(in_part)) + { + FD_SET((int)in_part->ch_fd, wfds); + if ((int)in_part->ch_fd >= maxfd) + maxfd = (int)in_part->ch_fd + 1; + } + } + return maxfd; +} +#else +/* + * Add write fds where we are waiting for writing to be possible. + */ + static int +channel_fill_poll_write(int nfd_in, struct pollfd *fds) +{ + int nfd = nfd_in; + channel_T *ch; + + FOR_ALL_CHANNELS(ch) + { + chanpart_T *in_part = &ch->ch_part[PART_IN]; + + if (in_part->ch_fd != INVALID_FD + && is_channel_write_remaining(in_part)) + { + in_part->ch_poll_idx = nfd; + fds[nfd].fd = in_part->ch_fd; + fds[nfd].events = POLLOUT; + ++nfd; + } + else + in_part->ch_poll_idx = -1; + } + return nfd; +} +#endif + +typedef enum { + CW_READY, + CW_NOT_READY, + CW_ERROR +} channel_wait_result; + +/* + * Check for reading from "fd" with "timeout" msec. + * Return CW_READY when there is something to read. + * Return CW_NOT_READY when there is nothing to read. + * Return CW_ERROR when there is an error. + */ + static channel_wait_result +channel_wait(channel_T *channel, sock_T fd, int timeout) +{ + if (timeout > 0) + ch_log(channel, "Waiting for up to %d msec", timeout); + +# ifdef MSWIN + if (fd != channel->CH_SOCK_FD) + { + DWORD nread; + int sleep_time; + DWORD deadline = GetTickCount() + timeout; + int delay = 1; + + // reading from a pipe, not a socket + while (TRUE) + { + int r = PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &nread, NULL); + + if (r && nread > 0) + return CW_READY; + + if (channel->ch_named_pipe) + { + DisconnectNamedPipe((HANDLE)fd); + ConnectNamedPipe((HANDLE)fd, NULL); + } + else if (r == 0) + return CW_ERROR; + + // perhaps write some buffer lines + channel_write_any_lines(); + + sleep_time = deadline - GetTickCount(); + if (sleep_time <= 0) + break; + // Wait for a little while. Very short at first, up to 10 msec + // after looping a few times. + if (sleep_time > delay) + sleep_time = delay; + Sleep(sleep_time); + delay = delay * 2; + if (delay > 10) + delay = 10; + } + } + else +#endif + { +#if defined(HAVE_SELECT) + struct timeval tval; + fd_set rfds; + fd_set wfds; + int ret; + int maxfd; + + tval.tv_sec = timeout / 1000; + tval.tv_usec = (timeout % 1000) * 1000; + for (;;) + { + FD_ZERO(&rfds); + FD_SET((int)fd, &rfds); + + // Write lines to a pipe when a pipe can be written to. Need to + // set this every time, some buffers may be done. + maxfd = (int)fd + 1; + FD_ZERO(&wfds); + maxfd = channel_fill_wfds(maxfd, &wfds); + + ret = select(maxfd, &rfds, &wfds, NULL, &tval); +# ifdef EINTR + SOCK_ERRNO; + if (ret == -1 && errno == EINTR) + continue; +# endif + if (ret > 0) + { + if (FD_ISSET(fd, &rfds)) + return CW_READY; + channel_write_any_lines(); + continue; + } + break; + } +#else + for (;;) + { + struct pollfd fds[MAX_OPEN_CHANNELS + 1]; + int nfd = 1; + + fds[0].fd = fd; + fds[0].events = POLLIN; + nfd = channel_fill_poll_write(nfd, fds); + if (poll(fds, nfd, timeout) > 0) + { + if (fds[0].revents & POLLIN) + return CW_READY; + channel_write_any_lines(); + continue; + } + break; + } +#endif + } + return CW_NOT_READY; +} + + static void +ch_close_part_on_error( + channel_T *channel, ch_part_T part, int is_err, char *func) +{ + char msg[] = "%s(): Read %s from ch_part[%d], closing"; + + if (is_err) + // Do not call emsg(), most likely the other end just exited. + ch_error(channel, msg, func, "error", part); + else + ch_log(channel, msg, func, "EOF", part); + + // Queue a "DETACH" netbeans message in the command queue in order to + // terminate the netbeans session later. Do not end the session here + // directly as we may be running in the context of a call to + // netbeans_parse_messages(): + // netbeans_parse_messages + // -> autocmd triggered while processing the netbeans cmd + // -> ui_breakcheck + // -> gui event loop or select loop + // -> channel_read() + // Only send "DETACH" for a netbeans channel. + if (channel->ch_nb_close_cb != NULL) + channel_save(channel, PART_SOCK, (char_u *)DETACH_MSG_RAW, + (int)STRLEN(DETACH_MSG_RAW), FALSE, "PUT "); + + // When reading is not possible close this part of the channel. Don't + // close the channel yet, there may be something to read on another part. + // When stdout and stderr use the same FD we get the error only on one of + // them, also close the other. + if (part == PART_OUT || part == PART_ERR) + { + ch_part_T other = part == PART_OUT ? PART_ERR : PART_OUT; + + if (channel->ch_part[part].ch_fd == channel->ch_part[other].ch_fd) + ch_close_part(channel, other); + } + ch_close_part(channel, part); + +#ifdef FEAT_GUI + // Stop listening to GUI events right away. + channel_gui_unregister_one(channel, part); +#endif +} + + static void +channel_close_now(channel_T *channel) +{ + ch_log(channel, "Closing channel because all readable fds are closed"); + if (channel->ch_nb_close_cb != NULL) + (*channel->ch_nb_close_cb)(); + channel_close(channel, TRUE); +} + +/* + * Read from channel "channel" for as long as there is something to read. + * "part" is PART_SOCK, PART_OUT or PART_ERR. + * The data is put in the read queue. No callbacks are invoked here. + */ + static void +channel_read(channel_T *channel, ch_part_T part, char *func) +{ + static char_u *buf = NULL; + int len = 0; + int readlen = 0; + sock_T fd; + int use_socket = FALSE; + + fd = channel->ch_part[part].ch_fd; + if (fd == INVALID_FD) + { + ch_error(channel, "channel_read() called while %s part is closed", + ch_part_names[part]); + return; + } + use_socket = fd == channel->CH_SOCK_FD; + + // Allocate a buffer to read into. + if (buf == NULL) + { + buf = alloc(MAXMSGSIZE); + if (buf == NULL) + return; // out of memory! + } + + // Keep on reading for as long as there is something to read. + // Use select() or poll() to avoid blocking on a message that is exactly + // MAXMSGSIZE long. + for (;;) + { + if (channel_wait(channel, fd, 0) != CW_READY) + break; + if (use_socket) + len = sock_read(fd, (char *)buf, MAXMSGSIZE); + else + len = fd_read(fd, (char *)buf, MAXMSGSIZE); + if (len <= 0) + break; // error or nothing more to read + + // Store the read message in the queue. + channel_save(channel, part, buf, len, FALSE, "RECV "); + readlen += len; + } + + // Reading a disconnection (readlen == 0), or an error. + if (readlen <= 0) + { + if (!channel->ch_keep_open) + ch_close_part_on_error(channel, part, (len < 0), func); + } +#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK) + else if (CH_HAS_GUI && gtk_main_level() > 0) + // signal the main loop that there is something to read + gtk_main_quit(); +#endif +} + +/* + * Read from RAW or NL "channel"/"part". Blocks until there is something to + * read or the timeout expires. + * When "raw" is TRUE don't block waiting on a NL. + * Does not trigger timers or handle messages. + * Returns what was read in allocated memory. + * Returns NULL in case of error or timeout. + */ + static char_u * +channel_read_block( + channel_T *channel, ch_part_T part, int timeout, int raw, int *outlen) +{ + char_u *buf; + char_u *msg; + ch_mode_T mode = channel->ch_part[part].ch_mode; + sock_T fd = channel->ch_part[part].ch_fd; + char_u *nl; + readq_T *node; + + ch_log(channel, "Blocking %s read, timeout: %d msec", + mode == CH_MODE_RAW ? "RAW" : "NL", timeout); + + while (TRUE) + { + node = channel_peek(channel, part); + if (node != NULL) + { + if (mode == CH_MODE_RAW || (mode == CH_MODE_NL + && channel_first_nl(node) != NULL)) + // got a complete message + break; + if (channel_collapse(channel, part, mode == CH_MODE_NL) == OK) + continue; + // If not blocking or nothing more is coming then return what we + // have. + if (raw || fd == INVALID_FD) + break; + } + + // Wait for up to the channel timeout. + if (fd == INVALID_FD) + return NULL; + if (channel_wait(channel, fd, timeout) != CW_READY) + { + ch_log(channel, "Timed out"); + return NULL; + } + channel_read(channel, part, "channel_read_block"); + } + + // We have a complete message now. + if (mode == CH_MODE_RAW || outlen != NULL) + { + msg = channel_get_all(channel, part, outlen); + } + else + { + char_u *p; + + buf = node->rq_buffer; + nl = channel_first_nl(node); + + // Convert NUL to NL, the internal representation. + for (p = buf; (nl == NULL || p < nl) && p < buf + node->rq_buflen; ++p) + if (*p == NUL) + *p = NL; + + if (nl == NULL) + { + // must be a closed channel with missing NL + msg = channel_get(channel, part, NULL); + } + else if (nl + 1 == buf + node->rq_buflen) + { + // get the whole buffer + msg = channel_get(channel, part, NULL); + *nl = NUL; + } + else + { + // Copy the message into allocated memory and remove it from the + // buffer. + msg = vim_strnsave(buf, nl - buf); + channel_consume(channel, part, (int)(nl - buf) + 1); + } + } + if (ch_log_active()) + ch_log(channel, "Returning %d bytes", (int)STRLEN(msg)); + return msg; +} + +static int channel_blocking_wait = 0; + +/* + * Return TRUE if in a blocking wait that might trigger callbacks. + */ + int +channel_in_blocking_wait(void) +{ + return channel_blocking_wait > 0; +} + +/* + * Read one JSON message with ID "id" from "channel"/"part" and store the + * result in "rettv". + * When "id" is -1 accept any message; + * Blocks until the message is received or the timeout is reached. + * In corner cases this can be called recursively, that is why ch_block_ids is + * a list. + */ + static int +channel_read_json_block( + channel_T *channel, + ch_part_T part, + int timeout_arg, + int id, + typval_T **rettv) +{ + int more; + sock_T fd; + int timeout; + chanpart_T *chanpart = &channel->ch_part[part]; + ch_mode_T mode = channel->ch_part[part].ch_mode; + int retval = FAIL; + + ch_log(channel, "Blocking read JSON for id %d", id); + ++channel_blocking_wait; + + if (id >= 0) + channel_add_block_id(chanpart, id); + + for (;;) + { + if (mode == CH_MODE_LSP) + // In the "lsp" mode, the http header and the json payload may be + // received in multiple messages. So concatenate all the received + // messages. + (void)channel_collapse(channel, part, FALSE); + + more = channel_parse_json(channel, part); + + // search for message "id" + if (channel_get_json(channel, part, id, TRUE, rettv) == OK) + { + ch_log(channel, "Received JSON for id %d", id); + retval = OK; + break; + } + + if (!more) + { + void *prev_readahead_ptr = channel_readahead_pointer(channel, part); + void *readahead_ptr; + + // Handle any other messages in the queue. If done some more + // messages may have arrived. + if (channel_parse_messages()) + continue; + + // channel_parse_messages() may fill the queue with new data to + // process. Only loop when the readahead changed, otherwise we + // would busy-loop. + readahead_ptr = channel_readahead_pointer(channel, part); + if (readahead_ptr != NULL && readahead_ptr != prev_readahead_ptr) + continue; + + // Wait for up to the timeout. If there was an incomplete message + // use the deadline for that. + timeout = timeout_arg; + if (chanpart->ch_wait_len > 0) + { +#ifdef MSWIN + timeout = chanpart->ch_deadline - GetTickCount() + 1; +#else + { + struct timeval now_tv; + + gettimeofday(&now_tv, NULL); + timeout = (chanpart->ch_deadline.tv_sec + - now_tv.tv_sec) * 1000 + + (chanpart->ch_deadline.tv_usec + - now_tv.tv_usec) / 1000 + + 1; + } +#endif + if (timeout < 0) + { + // Something went wrong, channel_parse_json() didn't + // discard message. Cancel waiting. + chanpart->ch_wait_len = 0; + timeout = timeout_arg; + } + else if (timeout > timeout_arg) + timeout = timeout_arg; + } + fd = chanpart->ch_fd; + if (fd == INVALID_FD + || channel_wait(channel, fd, timeout) != CW_READY) + { + if (timeout == timeout_arg) + { + if (fd != INVALID_FD) + ch_log(channel, "Timed out on id %d", id); + break; + } + } + else + channel_read(channel, part, "channel_read_json_block"); + } + } + if (id >= 0) + channel_remove_block_id(chanpart, id); + --channel_blocking_wait; + + return retval; +} + +/* + * Get the channel from the argument. + * Returns NULL if the handle is invalid. + * When "check_open" is TRUE check that the channel can be used. + * When "reading" is TRUE "check_open" considers typeahead useful. + * "part" is used to check typeahead, when PART_COUNT use the default part. + */ + channel_T * +get_channel_arg(typval_T *tv, int check_open, int reading, ch_part_T part) +{ + channel_T *channel = NULL; + int has_readahead = FALSE; + + if (tv->v_type == VAR_JOB) + { + if (tv->vval.v_job != NULL) + channel = tv->vval.v_job->jv_channel; + } + else if (tv->v_type == VAR_CHANNEL) + { + channel = tv->vval.v_channel; + } + else + { + semsg(_(e_invalid_argument_str), tv_get_string(tv)); + return NULL; + } + if (channel != NULL && reading) + has_readahead = channel_has_readahead(channel, + part != PART_COUNT ? part : channel_part_read(channel)); + + if (check_open && (channel == NULL || (!channel_is_open(channel) + && !(reading && has_readahead)))) + { + emsg(_(e_not_an_open_channel)); + return NULL; + } + return channel; +} + +/* + * Common for ch_read() and ch_readraw(). + */ + static void +common_channel_read(typval_T *argvars, typval_T *rettv, int raw, int blob) +{ + channel_T *channel; + ch_part_T part = PART_COUNT; + jobopt_T opt; + int mode; + int timeout; + int id = -1; + typval_T *listtv = NULL; + + // return an empty string by default + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + if (in_vim9script() + && (check_for_chan_or_job_arg(argvars, 0) == FAIL + || check_for_opt_dict_arg(argvars, 1) == FAIL)) + return; + + clear_job_options(&opt); + if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID, 0) + == FAIL) + goto theend; + + if (opt.jo_set & JO_PART) + part = opt.jo_part; + channel = get_channel_arg(&argvars[0], TRUE, TRUE, part); + if (channel == NULL) + goto theend; + + if (part == PART_COUNT) + part = channel_part_read(channel); + mode = channel_get_mode(channel, part); + timeout = channel_get_timeout(channel, part); + if (opt.jo_set & JO_TIMEOUT) + timeout = opt.jo_timeout; + + if (blob) + { + int outlen = 0; + char_u *p = channel_read_block(channel, part, + timeout, TRUE, &outlen); + if (p != NULL) + { + blob_T *b = blob_alloc(); + + if (b != NULL) + { + b->bv_ga.ga_len = outlen; + if (ga_grow(&b->bv_ga, outlen) == FAIL) + blob_free(b); + else + { + memcpy(b->bv_ga.ga_data, p, outlen); + rettv_blob_set(rettv, b); + } + } + vim_free(p); + } + } + else if (raw || mode == CH_MODE_RAW || mode == CH_MODE_NL) + rettv->vval.v_string = channel_read_block(channel, part, + timeout, raw, NULL); + else + { + if (opt.jo_set & JO_ID) + id = opt.jo_id; + channel_read_json_block(channel, part, timeout, id, &listtv); + if (listtv != NULL) + { + *rettv = *listtv; + vim_free(listtv); + } + else + { + rettv->v_type = VAR_SPECIAL; + rettv->vval.v_number = VVAL_NONE; + } + } + +theend: + free_job_options(&opt); +} + +#if defined(MSWIN) || defined(__HAIKU__) || defined(FEAT_GUI) || defined(PROTO) +/* + * Check the channels for anything that is ready to be read. + * The data is put in the read queue. + * if "only_keep_open" is TRUE only check channels where ch_keep_open is set. + */ + void +channel_handle_events(int only_keep_open) +{ + channel_T *channel; + ch_part_T part; + sock_T fd; + + FOR_ALL_CHANNELS(channel) + { + if (only_keep_open && !channel->ch_keep_open) + continue; + + // check the socket and pipes + for (part = PART_SOCK; part < PART_IN; ++part) + { + fd = channel->ch_part[part].ch_fd; + if (fd == INVALID_FD) + continue; + + int r = channel_wait(channel, fd, 0); + + if (r == CW_READY) + channel_read(channel, part, "channel_handle_events"); + else if (r == CW_ERROR) + ch_close_part_on_error(channel, part, TRUE, + "channel_handle_events"); + } + +# ifdef __HAIKU__ + // Workaround for Haiku: Since select/poll cannot detect EOF from tty, + // should close fds when the job has finished if 'channel' connects to + // the pty. + if (channel->ch_job != NULL) + { + job_T *job = channel->ch_job; + + if (job->jv_tty_out != NULL && job->jv_status == JOB_FINISHED) + for (part = PART_SOCK; part < PART_COUNT; ++part) + ch_close_part(channel, part); + } +# endif + } +} +#endif + +# if defined(FEAT_GUI) || defined(PROTO) +/* + * Return TRUE when there is any channel with a keep_open flag. + */ + int +channel_any_keep_open(void) +{ + channel_T *channel; + + FOR_ALL_CHANNELS(channel) + if (channel->ch_keep_open) + return TRUE; + return FALSE; +} +# endif + +/* + * Set "channel"/"part" to non-blocking. + * Only works for sockets and pipes. + */ + void +channel_set_nonblock(channel_T *channel, ch_part_T part) +{ + chanpart_T *ch_part = &channel->ch_part[part]; + int fd = ch_part->ch_fd; + + if (fd == INVALID_FD) + return; + +#ifdef MSWIN + u_long val = 1; + + ioctlsocket(fd, FIONBIO, &val); +#else + (void)fcntl(fd, F_SETFL, O_NONBLOCK); +#endif + ch_part->ch_nonblocking = TRUE; +} + +/* + * Write "buf" (NUL terminated string) to "channel"/"part". + * When "fun" is not NULL an error message might be given. + * Return FAIL or OK. + */ + int +channel_send( + channel_T *channel, + ch_part_T part, + char_u *buf_arg, + int len_arg, + char *fun) +{ + int res; + sock_T fd; + chanpart_T *ch_part = &channel->ch_part[part]; + int did_use_queue = FALSE; + + fd = ch_part->ch_fd; + if (fd == INVALID_FD) + { + if (!channel->ch_error && fun != NULL) + { + ch_error(channel, "%s(): write while not connected", fun); + semsg(_(e_str_write_while_not_connected), fun); + } + channel->ch_error = TRUE; + return FAIL; + } + + if (channel->ch_nonblock && !ch_part->ch_nonblocking) + channel_set_nonblock(channel, part); + + if (ch_log_active()) + { + ch_log_literal("SEND ", channel, part, buf_arg, len_arg); + did_repeated_msg = 0; + } + + for (;;) + { + writeq_T *wq = &ch_part->ch_writeque; + char_u *buf; + int len; + + if (wq->wq_next != NULL) + { + // first write what was queued + buf = wq->wq_next->wq_ga.ga_data; + len = wq->wq_next->wq_ga.ga_len; + did_use_queue = TRUE; + } + else + { + if (len_arg == 0) + // nothing to write, called from channel_select_check() + return OK; + buf = buf_arg; + len = len_arg; + } + + if (part == PART_SOCK) + res = sock_write(fd, (char *)buf, len); + else + { + res = fd_write(fd, (char *)buf, len); +#ifdef MSWIN + if (channel->ch_named_pipe && res < 0) + { + DisconnectNamedPipe((HANDLE)fd); + ConnectNamedPipe((HANDLE)fd, NULL); + } +#endif + } + if (res < 0 && (errno == EWOULDBLOCK +#ifdef EAGAIN + || errno == EAGAIN +#endif + )) + res = 0; // nothing got written + + if (res >= 0 && ch_part->ch_nonblocking) + { + writeq_T *entry = wq->wq_next; + + if (did_use_queue) + ch_log(channel, "Sent %d bytes now", res); + if (res == len) + { + // Wrote all the buf[len] bytes. + if (entry != NULL) + { + // Remove the entry from the write queue. + remove_from_writeque(wq, entry); + continue; + } + if (did_use_queue) + ch_log(channel, "Write queue empty"); + } + else + { + // Wrote only buf[res] bytes, can't write more now. + if (entry != NULL) + { + if (res > 0) + { + // Remove the bytes that were written. + mch_memmove(entry->wq_ga.ga_data, + (char *)entry->wq_ga.ga_data + res, + len - res); + entry->wq_ga.ga_len -= res; + } + buf = buf_arg; + len = len_arg; + } + else + { + buf += res; + len -= res; + } + ch_log(channel, "Adding %d bytes to the write queue", len); + + // Append the not written bytes of the argument to the write + // buffer. Limit entries to 4000 bytes. + if (wq->wq_prev != NULL + && wq->wq_prev->wq_ga.ga_len + len < 4000) + { + writeq_T *last = wq->wq_prev; + + // append to the last entry + if (len > 0 && ga_grow(&last->wq_ga, len) == OK) + { + mch_memmove((char *)last->wq_ga.ga_data + + last->wq_ga.ga_len, + buf, len); + last->wq_ga.ga_len += len; + } + } + else + { + writeq_T *last = ALLOC_ONE(writeq_T); + + if (last != NULL) + { + last->wq_prev = wq->wq_prev; + last->wq_next = NULL; + if (wq->wq_prev == NULL) + wq->wq_next = last; + else + wq->wq_prev->wq_next = last; + wq->wq_prev = last; + ga_init2(&last->wq_ga, 1, 1000); + if (len > 0 && ga_grow(&last->wq_ga, len) == OK) + { + mch_memmove(last->wq_ga.ga_data, buf, len); + last->wq_ga.ga_len = len; + } + } + } + } + } + else if (res != len) + { + if (!channel->ch_error && fun != NULL) + { + ch_error(channel, "%s(): write failed", fun); + semsg(_(e_str_write_failed), fun); + } + channel->ch_error = TRUE; + return FAIL; + } + + channel->ch_error = FALSE; + return OK; + } +} + +/* + * Common for "ch_sendexpr()" and "ch_sendraw()". + * Returns the channel if the caller should read the response. + * Sets "part_read" to the read fd. + * Otherwise returns NULL. + */ + static channel_T * +send_common( + typval_T *argvars, + char_u *text, + int len, + int id, + int eval, + jobopt_T *opt, + char *fun, + ch_part_T *part_read) +{ + channel_T *channel; + ch_part_T part_send; + + clear_job_options(opt); + channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); + if (channel == NULL) + return NULL; + part_send = channel_part_send(channel); + *part_read = channel_part_read(channel); + + if (get_job_options(&argvars[2], opt, JO_CALLBACK + JO_TIMEOUT, 0) == FAIL) + return NULL; + + // Set the callback. An empty callback means no callback and not reading + // the response. With "ch_evalexpr()" and "ch_evalraw()" a callback is not + // allowed. + if (opt->jo_callback.cb_name != NULL && *opt->jo_callback.cb_name != NUL) + { + if (eval) + { + semsg(_(e_cannot_use_callback_with_str), fun); + return NULL; + } + channel_set_req_callback(channel, *part_read, &opt->jo_callback, id); + } + + if (channel_send(channel, part_send, text, len, fun) == OK + && opt->jo_callback.cb_name == NULL) + return channel; + return NULL; +} + +/* + * common for "ch_evalexpr()" and "ch_sendexpr()" + */ + static void +ch_expr_common(typval_T *argvars, typval_T *rettv, int eval) +{ + char_u *text; + typval_T *listtv; + channel_T *channel; + int id; + ch_mode_T ch_mode; + ch_part_T part_send; + ch_part_T part_read; + jobopt_T opt; + int timeout; + int callback_present = FALSE; + + // return an empty string by default + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + if (in_vim9script() + && (check_for_chan_or_job_arg(argvars, 0) == FAIL + || check_for_opt_dict_arg(argvars, 2) == FAIL)) + return; + + channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); + if (channel == NULL) + return; + part_send = channel_part_send(channel); + + ch_mode = channel_get_mode(channel, part_send); + if (ch_mode == CH_MODE_RAW || ch_mode == CH_MODE_NL) + { + emsg(_(e_cannot_use_evalexpr_sendexpr_with_raw_or_nl_channel)); + return; + } + + if (ch_mode == CH_MODE_LSP) + { + dict_T *d; + dictitem_T *di; + + // return an empty dict by default + if (rettv_dict_alloc(rettv) == FAIL) + return; + + if (check_for_dict_arg(argvars, 1) == FAIL) + return; + + d = argvars[1].vval.v_dict; + di = dict_find(d, (char_u *)"id", -1); + if (di != NULL && di->di_tv.v_type != VAR_NUMBER) + { + // only number type is supported for the 'id' item + semsg(_(e_invalid_value_for_argument_str), "id"); + return; + } + + if (argvars[2].v_type == VAR_DICT) + if (dict_has_key(argvars[2].vval.v_dict, "callback")) + callback_present = TRUE; + + if (eval || callback_present) + { + // When evaluating an expression or sending an expression with a + // callback, always assign a generated ID + id = ++channel->ch_last_msg_id; + if (di == NULL) + dict_add_number(d, "id", id); + else + di->di_tv.vval.v_number = id; + } + else + { + // When sending an expression, if the message has an 'id' item, + // then use it. + id = 0; + if (di != NULL) + id = di->di_tv.vval.v_number; + } + if (!dict_has_key(d, "jsonrpc")) + dict_add_string(d, "jsonrpc", (char_u *)"2.0"); + text = json_encode_lsp_msg(&argvars[1]); + } + else + { + id = ++channel->ch_last_msg_id; + text = json_encode_nr_expr(id, &argvars[1], + (ch_mode == CH_MODE_JS ? JSON_JS : 0) | JSON_NL); + } + if (text == NULL) + return; + + channel = send_common(argvars, text, (int)STRLEN(text), id, eval, &opt, + eval ? "ch_evalexpr" : "ch_sendexpr", &part_read); + vim_free(text); + if (channel != NULL && eval) + { + if (opt.jo_set & JO_TIMEOUT) + timeout = opt.jo_timeout; + else + timeout = channel_get_timeout(channel, part_read); + if (channel_read_json_block(channel, part_read, timeout, id, &listtv) + == OK) + { + if (ch_mode == CH_MODE_LSP) + { + *rettv = *listtv; + // Change the type to avoid the value being freed. + listtv->v_type = VAR_NUMBER; + free_tv(listtv); + } + else + { + list_T *list = listtv->vval.v_list; + + // Move the item from the list and then change the type to + // avoid the value being freed. + *rettv = list->lv_u.mat.lv_last->li_tv; + list->lv_u.mat.lv_last->li_tv.v_type = VAR_NUMBER; + free_tv(listtv); + } + } + } + free_job_options(&opt); + if (ch_mode == CH_MODE_LSP && !eval && callback_present) + { + // if ch_sendexpr() is used to send a LSP message and a callback + // function is specified, then return the generated identifier for the + // message. The user can use this to cancel the request (if needed). + if (rettv->vval.v_dict != NULL) + dict_add_number(rettv->vval.v_dict, "id", id); + } +} + +/* + * common for "ch_evalraw()" and "ch_sendraw()" + */ + static void +ch_raw_common(typval_T *argvars, typval_T *rettv, int eval) +{ + char_u buf[NUMBUFLEN]; + char_u *text; + int len; + channel_T *channel; + ch_part_T part_read; + jobopt_T opt; + int timeout; + + // return an empty string by default + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + if (in_vim9script() + && (check_for_chan_or_job_arg(argvars, 0) == FAIL + || check_for_string_or_blob_arg(argvars, 1) == FAIL + || check_for_opt_dict_arg(argvars, 2) == FAIL)) + return; + + if (argvars[1].v_type == VAR_BLOB) + { + text = argvars[1].vval.v_blob->bv_ga.ga_data; + len = argvars[1].vval.v_blob->bv_ga.ga_len; + } + else + { + text = tv_get_string_buf(&argvars[1], buf); + len = (int)STRLEN(text); + } + channel = send_common(argvars, text, len, 0, eval, &opt, + eval ? "ch_evalraw" : "ch_sendraw", &part_read); + if (channel != NULL && eval) + { + if (opt.jo_set & JO_TIMEOUT) + timeout = opt.jo_timeout; + else + timeout = channel_get_timeout(channel, part_read); + rettv->vval.v_string = channel_read_block(channel, part_read, + timeout, TRUE, NULL); + } + free_job_options(&opt); +} + +#define KEEP_OPEN_TIME 20 // msec + +#if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO) +/* + * Add open channels to the poll struct. + * Return the adjusted struct index. + * The type of "fds" is hidden to avoid problems with the function proto. + */ + int +channel_poll_setup(int nfd_in, void *fds_in, int *towait) +{ + int nfd = nfd_in; + channel_T *channel; + struct pollfd *fds = fds_in; + ch_part_T part; + + FOR_ALL_CHANNELS(channel) + { + for (part = PART_SOCK; part < PART_IN; ++part) + { + chanpart_T *ch_part = &channel->ch_part[part]; + + if (ch_part->ch_fd != INVALID_FD) + { + if (channel->ch_keep_open) + { + // For unknown reason poll() returns immediately for a + // keep-open channel. Instead of adding it to the fds add + // a short timeout and check, like polling. + if (*towait < 0 || *towait > KEEP_OPEN_TIME) + *towait = KEEP_OPEN_TIME; + } + else + { + ch_part->ch_poll_idx = nfd; + fds[nfd].fd = ch_part->ch_fd; + fds[nfd].events = POLLIN; + nfd++; + } + } + else + channel->ch_part[part].ch_poll_idx = -1; + } + } + + nfd = channel_fill_poll_write(nfd, fds); + + return nfd; +} + +/* + * The type of "fds" is hidden to avoid problems with the function proto. + */ + int +channel_poll_check(int ret_in, void *fds_in) +{ + int ret = ret_in; + channel_T *channel; + struct pollfd *fds = fds_in; + ch_part_T part; + int idx; + chanpart_T *in_part; + + FOR_ALL_CHANNELS(channel) + { + for (part = PART_SOCK; part < PART_IN; ++part) + { + idx = channel->ch_part[part].ch_poll_idx; + + if (ret > 0 && idx != -1 && (fds[idx].revents & POLLIN)) + { + channel_read(channel, part, "channel_poll_check"); + --ret; + } + else if (channel->ch_part[part].ch_fd != INVALID_FD + && channel->ch_keep_open) + { + // polling a keep-open channel + channel_read(channel, part, "channel_poll_check_keep_open"); + } + } + + in_part = &channel->ch_part[PART_IN]; + idx = in_part->ch_poll_idx; + if (ret > 0 && idx != -1 && (fds[idx].revents & POLLOUT)) + { + channel_write_input(channel); + --ret; + } + } + + return ret; +} +#endif // UNIX && !HAVE_SELECT + +#if (!defined(MSWIN) && defined(HAVE_SELECT)) || defined(PROTO) + +/* + * The "fd_set" type is hidden to avoid problems with the function proto. + */ + int +channel_select_setup( + int maxfd_in, + void *rfds_in, + void *wfds_in, + struct timeval *tv, + struct timeval **tvp) +{ + int maxfd = maxfd_in; + channel_T *channel; + fd_set *rfds = rfds_in; + fd_set *wfds = wfds_in; + ch_part_T part; + + FOR_ALL_CHANNELS(channel) + { + for (part = PART_SOCK; part < PART_IN; ++part) + { + sock_T fd = channel->ch_part[part].ch_fd; + + if (fd != INVALID_FD) + { + if (channel->ch_keep_open) + { + // For unknown reason select() returns immediately for a + // keep-open channel. Instead of adding it to the rfds add + // a short timeout and check, like polling. + if (*tvp == NULL || tv->tv_sec > 0 + || tv->tv_usec > KEEP_OPEN_TIME * 1000) + { + *tvp = tv; + tv->tv_sec = 0; + tv->tv_usec = KEEP_OPEN_TIME * 1000; + } + } + else + { + FD_SET((int)fd, rfds); + if (maxfd < (int)fd) + maxfd = (int)fd; + } + } + } + } + + maxfd = channel_fill_wfds(maxfd, wfds); + + return maxfd; +} + +/* + * The "fd_set" type is hidden to avoid problems with the function proto. + */ + int +channel_select_check(int ret_in, void *rfds_in, void *wfds_in) +{ + int ret = ret_in; + channel_T *channel; + fd_set *rfds = rfds_in; + fd_set *wfds = wfds_in; + ch_part_T part; + chanpart_T *in_part; + + FOR_ALL_CHANNELS(channel) + { + for (part = PART_SOCK; part < PART_IN; ++part) + { + sock_T fd = channel->ch_part[part].ch_fd; + + if (ret > 0 && fd != INVALID_FD && FD_ISSET(fd, rfds)) + { + channel_read(channel, part, "channel_select_check"); + FD_CLR(fd, rfds); + --ret; + } + else if (fd != INVALID_FD && channel->ch_keep_open) + { + // polling a keep-open channel + channel_read(channel, part, "channel_select_check_keep_open"); + } + } + + in_part = &channel->ch_part[PART_IN]; + if (ret > 0 && in_part->ch_fd != INVALID_FD + && FD_ISSET(in_part->ch_fd, wfds)) + { + // Clear the flag first, ch_fd may change in channel_write_input(). + FD_CLR(in_part->ch_fd, wfds); + channel_write_input(channel); + --ret; + } + +# ifdef __HAIKU__ + // Workaround for Haiku: Since select/poll cannot detect EOF from tty, + // should close fds when the job has finished if 'channel' connects to + // the pty. + if (channel->ch_job != NULL) + { + job_T *job = channel->ch_job; + + if (job->jv_tty_out != NULL && job->jv_status == JOB_FINISHED) + for (part = PART_SOCK; part < PART_COUNT; ++part) + ch_close_part(channel, part); + } +# endif + } + + return ret; +} +#endif // !MSWIN && HAVE_SELECT + +/* + * Execute queued up commands. + * Invoked from the main loop when it's safe to execute received commands, + * and during a blocking wait for ch_evalexpr(). + * Return TRUE when something was done. + */ + int +channel_parse_messages(void) +{ + channel_T *channel = first_channel; + int ret = FALSE; + int r; + ch_part_T part = PART_SOCK; + static int recursive = 0; +#ifdef ELAPSED_FUNC + elapsed_T start_tv; +#endif + + // The code below may invoke callbacks, which might call us back. + // In a recursive call channels will not be closed. + ++recursive; + ++safe_to_invoke_callback; + +#ifdef ELAPSED_FUNC + ELAPSED_INIT(start_tv); +#endif + + // Only do this message when another message was given, otherwise we get + // lots of them. + if ((did_repeated_msg & REPEATED_MSG_LOOKING) == 0) + { + ch_log(NULL, "looking for messages on channels"); + // now we should also give the message for SafeState + did_repeated_msg = REPEATED_MSG_LOOKING; + } + while (channel != NULL) + { + if (recursive == 1) + { + if (channel_can_close(channel)) + { + channel->ch_to_be_closed = (1U << PART_COUNT); + channel_close_now(channel); + // channel may have been freed, start over + channel = first_channel; + continue; + } + if (channel->ch_to_be_freed || channel->ch_killing) + { + channel_free_contents(channel); + if (channel->ch_job != NULL) + channel->ch_job->jv_channel = NULL; + + // free the channel and then start over + channel_free_channel(channel); + channel = first_channel; + continue; + } + if (channel->ch_refcount == 0 && !channel_still_useful(channel)) + { + // channel is no longer useful, free it + channel_free(channel); + channel = first_channel; + part = PART_SOCK; + continue; + } + } + + if (channel->ch_part[part].ch_fd != INVALID_FD + || channel_has_readahead(channel, part)) + { + // Increase the refcount, in case the handler causes the channel + // to be unreferenced or closed. + ++channel->ch_refcount; + r = may_invoke_callback(channel, part); + if (r == OK) + ret = TRUE; + if (channel_unref(channel) || (r == OK +#ifdef ELAPSED_FUNC + // Limit the time we loop here to 100 msec, otherwise + // Vim becomes unresponsive when the callback takes + // more than a bit of time. + && ELAPSED_FUNC(start_tv) < 100L +#endif + )) + { + // channel was freed or something was done, start over + channel = first_channel; + part = PART_SOCK; + continue; + } + } + if (part < PART_ERR) + ++part; + else + { + channel = channel->ch_next; + part = PART_SOCK; + } + } + + if (channel_need_redraw) + { + channel_need_redraw = FALSE; + redraw_after_callback(TRUE, FALSE); + } + + --safe_to_invoke_callback; + --recursive; + + return ret; +} + +/* + * Return TRUE if any channel has readahead. That means we should not block on + * waiting for input. + */ + int +channel_any_readahead(void) +{ + channel_T *channel = first_channel; + ch_part_T part = PART_SOCK; + + while (channel != NULL) + { + if (channel_has_readahead(channel, part)) + return TRUE; + if (part < PART_ERR) + ++part; + else + { + channel = channel->ch_next; + part = PART_SOCK; + } + } + return FALSE; +} + +/* + * Mark references to lists used in channels. + */ + int +set_ref_in_channel(int copyID) +{ + int abort = FALSE; + channel_T *channel; + typval_T tv; + + for (channel = first_channel; !abort && channel != NULL; + channel = channel->ch_next) + if (channel_still_useful(channel)) + { + tv.v_type = VAR_CHANNEL; + tv.vval.v_channel = channel; + abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); + } + return abort; +} + +/* + * Return the "part" to write to for "channel". + */ + static ch_part_T +channel_part_send(channel_T *channel) +{ + if (channel->CH_SOCK_FD == INVALID_FD) + return PART_IN; + return PART_SOCK; +} + +/* + * Return the default "part" to read from for "channel". + */ + static ch_part_T +channel_part_read(channel_T *channel) +{ + if (channel->CH_SOCK_FD == INVALID_FD) + return PART_OUT; + return PART_SOCK; +} + +/* + * Return the mode of "channel"/"part" + * If "channel" is invalid returns CH_MODE_JSON. + */ + static ch_mode_T +channel_get_mode(channel_T *channel, ch_part_T part) +{ + if (channel == NULL) + return CH_MODE_JSON; + return channel->ch_part[part].ch_mode; +} + +/* + * Return the timeout of "channel"/"part" + */ + static int +channel_get_timeout(channel_T *channel, ch_part_T part) +{ + return channel->ch_part[part].ch_timeout; +} + +/* + * "ch_canread()" function + */ + void +f_ch_canread(typval_T *argvars, typval_T *rettv) +{ + channel_T *channel; + + rettv->vval.v_number = 0; + if (in_vim9script() && check_for_chan_or_job_arg(argvars, 0) == FAIL) + return; + + channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + if (channel != NULL) + rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK) + || channel_has_readahead(channel, PART_OUT) + || channel_has_readahead(channel, PART_ERR); +} + +/* + * "ch_close()" function + */ + void +f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) +{ + channel_T *channel; + + if (in_vim9script() && check_for_chan_or_job_arg(argvars, 0) == FAIL) + return; + + channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); + if (channel != NULL) + { + channel_close(channel, FALSE); + channel_clear(channel); + } +} + +/* + * "ch_close()" function + */ + void +f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED) +{ + channel_T *channel; + + if (in_vim9script() && check_for_chan_or_job_arg(argvars, 0) == FAIL) + return; + + channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); + if (channel != NULL) + channel_close_in(channel); +} + +/* + * "ch_getbufnr()" function + */ + void +f_ch_getbufnr(typval_T *argvars, typval_T *rettv) +{ + channel_T *channel; + + rettv->vval.v_number = -1; + + if (in_vim9script() + && (check_for_chan_or_job_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + if (channel == NULL) + return; + + char_u *what = tv_get_string(&argvars[1]); + int part; + if (STRCMP(what, "err") == 0) + part = PART_ERR; + else if (STRCMP(what, "out") == 0) + part = PART_OUT; + else if (STRCMP(what, "in") == 0) + part = PART_IN; + else + part = PART_SOCK; + if (channel->ch_part[part].ch_bufref.br_buf != NULL) + rettv->vval.v_number = + channel->ch_part[part].ch_bufref.br_buf->b_fnum; +} + +/* + * "ch_getjob()" function + */ + void +f_ch_getjob(typval_T *argvars, typval_T *rettv) +{ + channel_T *channel; + + if (in_vim9script() && check_for_chan_or_job_arg(argvars, 0) == FAIL) + return; + + channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + if (channel == NULL) + return; + + rettv->v_type = VAR_JOB; + rettv->vval.v_job = channel->ch_job; + if (channel->ch_job != NULL) + ++channel->ch_job->jv_refcount; +} + +/* + * "ch_info()" function + */ + void +f_ch_info(typval_T *argvars, typval_T *rettv UNUSED) +{ + channel_T *channel; + + if (in_vim9script() && check_for_chan_or_job_arg(argvars, 0) == FAIL) + return; + + channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + if (channel != NULL && rettv_dict_alloc(rettv) == OK) + channel_info(channel, rettv->vval.v_dict); +} + +/* + * "ch_open()" function + */ + void +f_ch_open(typval_T *argvars, typval_T *rettv) +{ + rettv->v_type = VAR_CHANNEL; + if (check_restricted() || check_secure()) + return; + rettv->vval.v_channel = channel_open_func(argvars); +} + +/* + * "ch_read()" function + */ + void +f_ch_read(typval_T *argvars, typval_T *rettv) +{ + common_channel_read(argvars, rettv, FALSE, FALSE); +} + +/* + * "ch_readblob()" function + */ + void +f_ch_readblob(typval_T *argvars, typval_T *rettv) +{ + common_channel_read(argvars, rettv, TRUE, TRUE); +} + +/* + * "ch_readraw()" function + */ + void +f_ch_readraw(typval_T *argvars, typval_T *rettv) +{ + common_channel_read(argvars, rettv, TRUE, FALSE); +} + +/* + * "ch_evalexpr()" function + */ + void +f_ch_evalexpr(typval_T *argvars, typval_T *rettv) +{ + ch_expr_common(argvars, rettv, TRUE); +} + +/* + * "ch_sendexpr()" function + */ + void +f_ch_sendexpr(typval_T *argvars, typval_T *rettv) +{ + ch_expr_common(argvars, rettv, FALSE); +} + +/* + * "ch_evalraw()" function + */ + void +f_ch_evalraw(typval_T *argvars, typval_T *rettv) +{ + ch_raw_common(argvars, rettv, TRUE); +} + +/* + * "ch_sendraw()" function + */ + void +f_ch_sendraw(typval_T *argvars, typval_T *rettv) +{ + ch_raw_common(argvars, rettv, FALSE); +} + +/* + * "ch_setoptions()" function + */ + void +f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED) +{ + channel_T *channel; + jobopt_T opt; + + if (in_vim9script() + && (check_for_chan_or_job_arg(argvars, 0) == FAIL + || check_for_dict_arg(argvars, 1) == FAIL)) + return; + + channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + if (channel == NULL) + return; + clear_job_options(&opt); + if (get_job_options(&argvars[1], &opt, + JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK) + channel_set_options(channel, &opt); + free_job_options(&opt); +} + +/* + * "ch_status()" function + */ + void +f_ch_status(typval_T *argvars, typval_T *rettv) +{ + channel_T *channel; + jobopt_T opt; + int part = -1; + + // return an empty string by default + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + if (in_vim9script() + && (check_for_chan_or_job_arg(argvars, 0) == FAIL + || check_for_opt_dict_arg(argvars, 1) == FAIL)) + return; + + channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + + if (argvars[1].v_type != VAR_UNKNOWN) + { + clear_job_options(&opt); + if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK + && (opt.jo_set & JO_PART)) + part = opt.jo_part; + } + + rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part)); +} + +/* + * Get a string with information about the channel in "varp" in "buf". + * "buf" must be at least NUMBUFLEN long. + */ + char_u * +channel_to_string_buf(typval_T *varp, char_u *buf) +{ + channel_T *channel = varp->vval.v_channel; + char *status = channel_status(channel, -1); + + if (channel == NULL) + vim_snprintf((char *)buf, NUMBUFLEN, "channel %s", status); + else + vim_snprintf((char *)buf, NUMBUFLEN, + "channel %d %s", channel->ch_id, status); + return buf; +} + +#endif // FEAT_JOB_CHANNEL diff --git a/src/charset.c b/src/charset.c new file mode 100644 index 0000000..826a768 --- /dev/null +++ b/src/charset.c @@ -0,0 +1,2411 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +#include "vim.h" + +#if defined(HAVE_WCHAR_H) +# include // for towupper() and towlower() +#endif + +static int win_nolbr_chartabsize(chartabsize_T *cts, int *headp); +static unsigned nr2hex(unsigned c); + +static int chartab_initialized = FALSE; + +// b_chartab[] is an array of 32 bytes, each bit representing one of the +// characters 0-255. +#define SET_CHARTAB(buf, c) (buf)->b_chartab[(unsigned)(c) >> 3] |= (1 << ((c) & 0x7)) +#define RESET_CHARTAB(buf, c) (buf)->b_chartab[(unsigned)(c) >> 3] &= ~(1 << ((c) & 0x7)) +#define GET_CHARTAB(buf, c) ((buf)->b_chartab[(unsigned)(c) >> 3] & (1 << ((c) & 0x7))) + +// table used below, see init_chartab() for an explanation +static char_u g_chartab[256]; + +/* + * Flags for g_chartab[]. + */ +#define CT_CELL_MASK 0x07 // mask: nr of display cells (1, 2 or 4) +#define CT_PRINT_CHAR 0x10 // flag: set for printable chars +#define CT_ID_CHAR 0x20 // flag: set for ID chars +#define CT_FNAME_CHAR 0x40 // flag: set for file name chars + +static int in_win_border(win_T *wp, colnr_T vcol); + +/* + * Fill g_chartab[]. Also fills curbuf->b_chartab[] with flags for keyword + * characters for current buffer. + * + * Depends on the option settings 'iskeyword', 'isident', 'isfname', + * 'isprint' and 'encoding'. + * + * The index in g_chartab[] depends on 'encoding': + * - For non-multi-byte index with the byte (same as the character). + * - For DBCS index with the first byte. + * - For UTF-8 index with the character (when first byte is up to 0x80 it is + * the same as the character, if the first byte is 0x80 and above it depends + * on further bytes). + * + * The contents of g_chartab[]: + * - The lower two bits, masked by CT_CELL_MASK, give the number of display + * cells the character occupies (1 or 2). Not valid for UTF-8 above 0x80. + * - CT_PRINT_CHAR bit is set when the character is printable (no need to + * translate the character before displaying it). Note that only DBCS + * characters can have 2 display cells and still be printable. + * - CT_FNAME_CHAR bit is set when the character can be in a file name. + * - CT_ID_CHAR bit is set when the character can be in an identifier. + * + * Return FAIL if 'iskeyword', 'isident', 'isfname' or 'isprint' option has an + * error, OK otherwise. + */ + int +init_chartab(void) +{ + return buf_init_chartab(curbuf, TRUE); +} + + int +buf_init_chartab( + buf_T *buf, + int global) // FALSE: only set buf->b_chartab[] +{ + int c; + int c2; + char_u *p; + int i; + int tilde; + int do_isalpha; + + if (global) + { + /* + * Set the default size for printable characters: + * From to '~' is 1 (printable), others are 2 (not printable). + * This also inits all 'isident' and 'isfname' flags to FALSE. + */ + c = 0; + while (c < ' ') + g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; + while (c <= '~') + g_chartab[c++] = 1 + CT_PRINT_CHAR; + while (c < 256) + { + // UTF-8: bytes 0xa0 - 0xff are printable (latin1) + if (enc_utf8 && c >= 0xa0) + g_chartab[c++] = CT_PRINT_CHAR + 1; + // euc-jp characters starting with 0x8e are single width + else if (enc_dbcs == DBCS_JPNU && c == 0x8e) + g_chartab[c++] = CT_PRINT_CHAR + 1; + // other double-byte chars can be printable AND double-width + else if (enc_dbcs != 0 && MB_BYTE2LEN(c) == 2) + g_chartab[c++] = CT_PRINT_CHAR + 2; + else + // the rest is unprintable by default + g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; + } + + // Assume that every multi-byte char is a filename character. + for (c = 1; c < 256; ++c) + if ((enc_dbcs != 0 && MB_BYTE2LEN(c) > 1) + || (enc_dbcs == DBCS_JPNU && c == 0x8e) + || (enc_utf8 && c >= 0xa0)) + g_chartab[c] |= CT_FNAME_CHAR; + } + + /* + * Init word char flags all to FALSE + */ + CLEAR_FIELD(buf->b_chartab); + if (enc_dbcs != 0) + for (c = 0; c < 256; ++c) + { + // double-byte characters are probably word characters + if (MB_BYTE2LEN(c) == 2) + SET_CHARTAB(buf, c); + } + + /* + * In lisp mode the '-' character is included in keywords. + */ + if (buf->b_p_lisp) + SET_CHARTAB(buf, '-'); + + // Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint' + // options Each option is a list of characters, character numbers or + // ranges, separated by commas, e.g.: "200-210,x,#-178,-" + for (i = global ? 0 : 3; i <= 3; ++i) + { + if (i == 0) + p = p_isi; // first round: 'isident' + else if (i == 1) + p = p_isp; // second round: 'isprint' + else if (i == 2) + p = p_isf; // third round: 'isfname' + else // i == 3 + p = buf->b_p_isk; // fourth round: 'iskeyword' + + while (*p) + { + tilde = FALSE; + do_isalpha = FALSE; + if (*p == '^' && p[1] != NUL) + { + tilde = TRUE; + ++p; + } + if (VIM_ISDIGIT(*p)) + c = getdigits(&p); + else if (has_mbyte) + c = mb_ptr2char_adv(&p); + else + c = *p++; + c2 = -1; + if (*p == '-' && p[1] != NUL) + { + ++p; + if (VIM_ISDIGIT(*p)) + c2 = getdigits(&p); + else if (has_mbyte) + c2 = mb_ptr2char_adv(&p); + else + c2 = *p++; + } + if (c <= 0 || c >= 256 || (c2 < c && c2 != -1) || c2 >= 256 + || !(*p == NUL || *p == ',')) + return FAIL; + + if (c2 == -1) // not a range + { + /* + * A single '@' (not "@-@"): + * Decide on letters being ID/printable/keyword chars with + * standard function isalpha(). This takes care of locale for + * single-byte characters). + */ + if (c == '@') + { + do_isalpha = TRUE; + c = 1; + c2 = 255; + } + else + c2 = c; + } + while (c <= c2) + { + // Use the MB_ functions here, because isalpha() doesn't + // work properly when 'encoding' is "latin1" and the locale is + // "C". + if (!do_isalpha || MB_ISLOWER(c) || MB_ISUPPER(c)) + { + if (i == 0) // (re)set ID flag + { + if (tilde) + g_chartab[c] &= ~CT_ID_CHAR; + else + g_chartab[c] |= CT_ID_CHAR; + } + else if (i == 1) // (re)set printable + { + if ((c < ' ' || c > '~' + // For double-byte we keep the cell width, so + // that we can detect it from the first byte. + ) && !(enc_dbcs && MB_BYTE2LEN(c) == 2)) + { + if (tilde) + { + g_chartab[c] = (g_chartab[c] & ~CT_CELL_MASK) + + ((dy_flags & DY_UHEX) ? 4 : 2); + g_chartab[c] &= ~CT_PRINT_CHAR; + } + else + { + g_chartab[c] = (g_chartab[c] & ~CT_CELL_MASK) + + 1; + g_chartab[c] |= CT_PRINT_CHAR; + } + } + } + else if (i == 2) // (re)set fname flag + { + if (tilde) + g_chartab[c] &= ~CT_FNAME_CHAR; + else + g_chartab[c] |= CT_FNAME_CHAR; + } + else // i == 3 (re)set keyword flag + { + if (tilde) + RESET_CHARTAB(buf, c); + else + SET_CHARTAB(buf, c); + } + } + ++c; + } + + c = *p; + p = skip_to_option_part(p); + if (c == ',' && *p == NUL) + // Trailing comma is not allowed. + return FAIL; + } + } + chartab_initialized = TRUE; + return OK; +} + +/* + * Translate any special characters in buf[bufsize] in-place. + * The result is a string with only printable characters, but if there is not + * enough room, not all characters will be translated. + */ + void +trans_characters( + char_u *buf, + int bufsize) +{ + int len; // length of string needing translation + int room; // room in buffer after string + char_u *trs; // translated character + int trs_len; // length of trs[] + + len = (int)STRLEN(buf); + room = bufsize - len; + while (*buf != 0) + { + // Assume a multi-byte character doesn't need translation. + if (has_mbyte && (trs_len = (*mb_ptr2len)(buf)) > 1) + len -= trs_len; + else + { + trs = transchar_byte(*buf); + trs_len = (int)STRLEN(trs); + if (trs_len > 1) + { + room -= trs_len - 1; + if (room <= 0) + return; + mch_memmove(buf + trs_len, buf + 1, (size_t)len); + } + mch_memmove(buf, trs, (size_t)trs_len); + --len; + } + buf += trs_len; + } +} + +/* + * Translate a string into allocated memory, replacing special chars with + * printable chars. Returns NULL when out of memory. + */ + char_u * +transstr(char_u *s) +{ + char_u *res; + char_u *p; + int l, len, c; + char_u hexbuf[11]; + + if (has_mbyte) + { + // Compute the length of the result, taking account of unprintable + // multi-byte characters. + len = 0; + p = s; + while (*p != NUL) + { + if ((l = (*mb_ptr2len)(p)) > 1) + { + c = (*mb_ptr2char)(p); + p += l; + if (vim_isprintc(c)) + len += l; + else + { + transchar_hex(hexbuf, c); + len += (int)STRLEN(hexbuf); + } + } + else + { + l = byte2cells(*p++); + if (l > 0) + len += l; + else + len += 4; // illegal byte sequence + } + } + res = alloc(len + 1); + } + else + res = alloc(vim_strsize(s) + 1); + + if (res == NULL) + return NULL; + + *res = NUL; + p = s; + while (*p != NUL) + { + if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) + { + c = (*mb_ptr2char)(p); + if (vim_isprintc(c)) + STRNCAT(res, p, l); // append printable multi-byte char + else + transchar_hex(res + STRLEN(res), c); + p += l; + } + else + STRCAT(res, transchar_byte(*p++)); + } + return res; +} + +/* + * Convert the string "str[orglen]" to do ignore-case comparing. Uses the + * current locale. + * When "buf" is NULL returns an allocated string (NULL for out-of-memory). + * Otherwise puts the result in "buf[buflen]". + */ + char_u * +str_foldcase( + char_u *str, + int orglen, + char_u *buf, + int buflen) +{ + garray_T ga; + int i; + int len = orglen; + +#define GA_CHAR(i) ((char_u *)ga.ga_data)[i] +#define GA_PTR(i) ((char_u *)ga.ga_data + (i)) +#define STR_CHAR(i) (buf == NULL ? GA_CHAR(i) : buf[i]) +#define STR_PTR(i) (buf == NULL ? GA_PTR(i) : buf + (i)) + + // Copy "str" into "buf" or allocated memory, unmodified. + if (buf == NULL) + { + ga_init2(&ga, 1, 10); + if (ga_grow(&ga, len + 1) == FAIL) + return NULL; + mch_memmove(ga.ga_data, str, (size_t)len); + ga.ga_len = len; + } + else + { + if (len >= buflen) // Ugly! + len = buflen - 1; + mch_memmove(buf, str, (size_t)len); + } + if (buf == NULL) + GA_CHAR(len) = NUL; + else + buf[len] = NUL; + + // Make each character lower case. + i = 0; + while (STR_CHAR(i) != NUL) + { + if (enc_utf8 || (has_mbyte && MB_BYTE2LEN(STR_CHAR(i)) > 1)) + { + if (enc_utf8) + { + int c = utf_ptr2char(STR_PTR(i)); + int olen = utf_ptr2len(STR_PTR(i)); + int lc = utf_tolower(c); + + // Only replace the character when it is not an invalid + // sequence (ASCII character or more than one byte) and + // utf_tolower() doesn't return the original character. + if ((c < 0x80 || olen > 1) && c != lc) + { + int nlen = utf_char2len(lc); + + // If the byte length changes need to shift the following + // characters forward or backward. + if (olen != nlen) + { + if (nlen > olen) + { + if (buf == NULL + ? ga_grow(&ga, nlen - olen + 1) == FAIL + : len + nlen - olen >= buflen) + { + // out of memory, keep old char + lc = c; + nlen = olen; + } + } + if (olen != nlen) + { + if (buf == NULL) + { + STRMOVE(GA_PTR(i) + nlen, GA_PTR(i) + olen); + ga.ga_len += nlen - olen; + } + else + { + STRMOVE(buf + i + nlen, buf + i + olen); + len += nlen - olen; + } + } + } + (void)utf_char2bytes(lc, STR_PTR(i)); + } + } + // skip to next multi-byte char + i += (*mb_ptr2len)(STR_PTR(i)); + } + else + { + if (buf == NULL) + GA_CHAR(i) = TOLOWER_LOC(GA_CHAR(i)); + else + buf[i] = TOLOWER_LOC(buf[i]); + ++i; + } + } + + if (buf == NULL) + return (char_u *)ga.ga_data; + return buf; +} + +/* + * Catch 22: g_chartab[] can't be initialized before the options are + * initialized, and initializing options may cause transchar() to be called! + * When chartab_initialized == FALSE don't use g_chartab[]. + * Does NOT work for multi-byte characters, c must be <= 255. + * Also doesn't work for the first byte of a multi-byte, "c" must be a + * character! + */ +static char_u transchar_charbuf[7]; + + char_u * +transchar(int c) +{ + return transchar_buf(curbuf, c); +} + + char_u * +transchar_buf(buf_T *buf, int c) +{ + int i; + + i = 0; + if (IS_SPECIAL(c)) // special key code, display as ~@ char + { + transchar_charbuf[0] = '~'; + transchar_charbuf[1] = '@'; + i = 2; + c = K_SECOND(c); + } + + if ((!chartab_initialized && ((c >= ' ' && c <= '~'))) + || (c < 256 && vim_isprintc_strict(c))) + { + // printable character + transchar_charbuf[i] = c; + transchar_charbuf[i + 1] = NUL; + } + else + transchar_nonprint(buf, transchar_charbuf + i, c); + return transchar_charbuf; +} + +/* + * Like transchar(), but called with a byte instead of a character. Checks + * for an illegal UTF-8 byte. Uses 'fileformat' of the current buffer. + */ + char_u * +transchar_byte(int c) +{ + return transchar_byte_buf(curbuf, c); +} + +/* + * Like transchar_buf(), but called with a byte instead of a character. Checks + * for an illegal UTF-8 byte. Uses 'fileformat' of "buf", unless it is NULL. + */ + char_u * +transchar_byte_buf(buf_T *buf, int c) +{ + if (enc_utf8 && c >= 0x80) + { + transchar_nonprint(buf, transchar_charbuf, c); + return transchar_charbuf; + } + return transchar_buf(buf, c); +} +/* + * Convert non-printable character to two or more printable characters in + * "charbuf[]". "charbuf" needs to be able to hold five bytes. + * Does NOT work for multi-byte characters, c must be <= 255. + */ + void +transchar_nonprint(buf_T *buf, char_u *charbuf, int c) +{ + if (c == NL) + c = NUL; // we use newline in place of a NUL + else if (buf != NULL && c == CAR && get_fileformat(buf) == EOL_MAC) + c = NL; // we use CR in place of NL in this case + + if (dy_flags & DY_UHEX) // 'display' has "uhex" + transchar_hex(charbuf, c); + + else if (c <= 0x7f) // 0x00 - 0x1f and 0x7f + { + charbuf[0] = '^'; + charbuf[1] = c ^ 0x40; // DEL displayed as ^? + charbuf[2] = NUL; + } + else if (enc_utf8) + { + transchar_hex(charbuf, c); + } + else if (c >= ' ' + 0x80 && c <= '~' + 0x80) // 0xa0 - 0xfe + { + charbuf[0] = '|'; + charbuf[1] = c - 0x80; + charbuf[2] = NUL; + } + else // 0x80 - 0x9f and 0xff + { + charbuf[0] = '~'; + charbuf[1] = (c - 0x80) ^ 0x40; // 0xff displayed as ~? + charbuf[2] = NUL; + } +} + + void +transchar_hex(char_u *buf, int c) +{ + int i = 0; + + buf[0] = '<'; + if (c > 255) + { + buf[++i] = nr2hex((unsigned)c >> 12); + buf[++i] = nr2hex((unsigned)c >> 8); + } + buf[++i] = nr2hex((unsigned)c >> 4); + buf[++i] = nr2hex((unsigned)c); + buf[++i] = '>'; + buf[++i] = NUL; +} + +/* + * Convert the lower 4 bits of byte "c" to its hex character. + * Lower case letters are used to avoid the confusion of being 0xf1 or + * function key 1. + */ + static unsigned +nr2hex(unsigned c) +{ + if ((c & 0xf) <= 9) + return (c & 0xf) + '0'; + return (c & 0xf) - 10 + 'a'; +} + +/* + * Return number of display cells occupied by byte "b". + * Caller must make sure 0 <= b <= 255. + * For multi-byte mode "b" must be the first byte of a character. + * A TAB is counted as two cells: "^I". + * For UTF-8 mode this will return 0 for bytes >= 0x80, because the number of + * cells depends on further bytes. + */ + int +byte2cells(int b) +{ + if (enc_utf8 && b >= 0x80) + return 0; + return (g_chartab[b] & CT_CELL_MASK); +} + +/* + * Return number of display cells occupied by character "c". + * "c" can be a special key (negative number) in which case 3 or 4 is returned. + * A TAB is counted as two cells: "^I" or four: "<09>". + */ + int +char2cells(int c) +{ + if (IS_SPECIAL(c)) + return char2cells(K_SECOND(c)) + 2; + if (c >= 0x80) + { + // UTF-8: above 0x80 need to check the value + if (enc_utf8) + return utf_char2cells(c); + // DBCS: double-byte means double-width, except for euc-jp with first + // byte 0x8e + if (enc_dbcs != 0 && c >= 0x100) + { + if (enc_dbcs == DBCS_JPNU && ((unsigned)c >> 8) == 0x8e) + return 1; + return 2; + } + } + return (g_chartab[c & 0xff] & CT_CELL_MASK); +} + +/* + * Return number of display cells occupied by character at "*p". + * A TAB is counted as two cells: "^I" or four: "<09>". + */ + int +ptr2cells(char_u *p) +{ + if (!has_mbyte) + return byte2cells(*p); + + // For UTF-8 we need to look at more bytes if the first byte is >= 0x80. + if (enc_utf8 && *p >= 0x80) + return utf_ptr2cells(p); + // For DBCS we can tell the cell count from the first byte. + return (g_chartab[*p] & CT_CELL_MASK); +} + +/* + * Return the number of character cells string "s" will take on the screen, + * counting TABs as two characters: "^I". + */ + int +vim_strsize(char_u *s) +{ + return vim_strnsize(s, (int)MAXCOL); +} + +/* + * Return the number of character cells string "s[len]" will take on the + * screen, counting TABs as two characters: "^I". + */ + int +vim_strnsize(char_u *s, int len) +{ + int size = 0; + + while (*s != NUL && --len >= 0) + { + int l = (*mb_ptr2len)(s); + + size += ptr2cells(s); + s += l; + len -= l - 1; + } + + return size; +} + +/* + * Return the number of characters 'c' will take on the screen, taking + * into account the size of a tab. + * Use a define to make it fast, this is used very often!!! + * Also see getvcol() below. + */ + +#ifdef FEAT_VARTABS +# define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \ + if (*(p) == TAB && (!(wp)->w_p_list || (wp)->w_lcs_chars.tab1)) \ + { \ + return tabstop_padding(col, (buf)->b_p_ts, (buf)->b_p_vts_array); \ + } \ + else \ + return ptr2cells(p); +#else +# define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \ + if (*(p) == TAB && (!(wp)->w_p_list || wp->w_lcs_chars.tab1)) \ + { \ + int ts; \ + ts = (buf)->b_p_ts; \ + return (int)(ts - (col % ts)); \ + } \ + else \ + return ptr2cells(p); +#endif + + int +chartabsize(char_u *p, colnr_T col) +{ + RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, p, col) +} + +#ifdef FEAT_LINEBREAK + static int +win_chartabsize(win_T *wp, char_u *p, colnr_T col) +{ + RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, p, col) +} +#endif + +/* + * Return the number of characters the string "s" will take on the screen, + * taking into account the size of a tab. + * Does not handle text properties, since "s" is not a buffer line. + */ + int +linetabsize_str(char_u *s) +{ + return linetabsize_col(0, s); +} + +/* + * Like linetabsize_str(), but "s" starts at column "startcol". + */ + int +linetabsize_col(int startcol, char_u *s) +{ + chartabsize_T cts; + + init_chartabsize_arg(&cts, curwin, 0, startcol, s, s); + while (*cts.cts_ptr != NUL) + cts.cts_vcol += lbr_chartabsize_adv(&cts); +#ifdef FEAT_PROP_POPUP + if (cts.cts_has_prop_with_text && cts.cts_ptr == cts.cts_line) + { + // check for virtual text in an empty line + (void)lbr_chartabsize_adv(&cts); + cts.cts_vcol += cts.cts_cur_text_width; + } +#endif + clear_chartabsize_arg(&cts); + return (int)cts.cts_vcol; +} + +/* + * Like linetabsize_str(), but for a given window instead of the current one. + */ + int +win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len) +{ + chartabsize_T cts; + + init_chartabsize_arg(&cts, wp, lnum, 0, line, line); + win_linetabsize_cts(&cts, len); + clear_chartabsize_arg(&cts); + return (int)cts.cts_vcol; +} + +/* + * Return the number of cells line "lnum" of window "wp" will take on the + * screen, taking into account the size of a tab and text properties. + */ + int +linetabsize(win_T *wp, linenr_T lnum) +{ + return win_linetabsize(wp, lnum, + ml_get_buf(wp->w_buffer, lnum, FALSE), (colnr_T)MAXCOL); +} + + void +win_linetabsize_cts(chartabsize_T *cts, colnr_T len) +{ +#ifdef FEAT_PROP_POPUP + cts->cts_with_trailing = len == MAXCOL; +#endif + for ( ; *cts->cts_ptr != NUL && (len == MAXCOL || cts->cts_ptr < cts->cts_line + len); + MB_PTR_ADV(cts->cts_ptr)) + cts->cts_vcol += win_lbr_chartabsize(cts, NULL); +#ifdef FEAT_PROP_POPUP + // check for a virtual text on an empty line + if (cts->cts_has_prop_with_text && *cts->cts_ptr == NUL + && cts->cts_ptr == cts->cts_line) + { + (void)win_lbr_chartabsize(cts, NULL); + cts->cts_vcol += cts->cts_cur_text_width; + + // when properties are above or below the empty line must also be + // counted + if (cts->cts_prop_lines > 0) + ++cts->cts_vcol; + } +#endif +} + +/* + * Return TRUE if 'c' is a normal identifier character: + * Letters and characters from the 'isident' option. + */ + int +vim_isIDc(int c) +{ + return (c > 0 && c < 0x100 && (g_chartab[c] & CT_ID_CHAR)); +} + +/* + * Like vim_isIDc() but not using the 'isident' option: letters, numbers and + * underscore. + */ + int +vim_isNormalIDc(int c) +{ + return ASCII_ISALNUM(c) || c == '_'; +} + +/* + * return TRUE if 'c' is a keyword character: Letters and characters from + * 'iskeyword' option for the current buffer. + * For multi-byte characters mb_get_class() is used (builtin rules). + */ + int +vim_iswordc(int c) +{ + return vim_iswordc_buf(c, curbuf); +} + + int +vim_iswordc_buf(int c, buf_T *buf) +{ + if (c >= 0x100) + { + if (enc_dbcs != 0) + return dbcs_class((unsigned)c >> 8, (unsigned)(c & 0xff)) >= 2; + if (enc_utf8) + return utf_class_buf(c, buf) >= 2; + return FALSE; + } + return (c > 0 && GET_CHARTAB(buf, c) != 0); +} + +/* + * Just like vim_iswordc() but uses a pointer to the (multi-byte) character. + */ + int +vim_iswordp(char_u *p) +{ + return vim_iswordp_buf(p, curbuf); +} + + int +vim_iswordp_buf(char_u *p, buf_T *buf) +{ + int c = *p; + + if (has_mbyte && MB_BYTE2LEN(c) > 1) + c = (*mb_ptr2char)(p); + return vim_iswordc_buf(c, buf); +} + +/* + * Return TRUE if 'c' is a valid file-name character as specified with the + * 'isfname' option. + * Assume characters above 0x100 are valid (multi-byte). + * To be used for commands like "gf". + */ + int +vim_isfilec(int c) +{ + return (c >= 0x100 || (c > 0 && (g_chartab[c] & CT_FNAME_CHAR))); +} + +/* + * Return TRUE if 'c' is a valid file-name character, including characters left + * out of 'isfname' to make "gf" work, such as comma, space, '@', etc. + */ + int +vim_is_fname_char(int c) +{ + return vim_isfilec(c) || c == ',' || c == ' ' || c == '@'; +} + +/* + * return TRUE if 'c' is a valid file-name character or a wildcard character + * Assume characters above 0x100 are valid (multi-byte). + * Explicitly interpret ']' as a wildcard character as mch_has_wildcard("]") + * returns false. + */ + int +vim_isfilec_or_wc(int c) +{ + char_u buf[2]; + + buf[0] = (char_u)c; + buf[1] = NUL; + return vim_isfilec(c) || c == ']' || mch_has_wildcard(buf); +} + +/* + * Return TRUE if 'c' is a printable character. + * Assume characters above 0x100 are printable (multi-byte), except for + * Unicode. + */ + int +vim_isprintc(int c) +{ + if (enc_utf8 && c >= 0x100) + return utf_printable(c); + return (c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR))); +} + +/* + * Strict version of vim_isprintc(c), don't return TRUE if "c" is the head + * byte of a double-byte character. + */ + int +vim_isprintc_strict(int c) +{ + if (enc_dbcs != 0 && c < 0x100 && MB_BYTE2LEN(c) > 1) + return FALSE; + if (enc_utf8 && c >= 0x100) + return utf_printable(c); + return (c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR))); +} + +/* + * Prepare the structure passed to chartabsize functions. + * "line" is the start of the line, "ptr" is the first relevant character. + * When "lnum" is zero do not use text properties that insert text. + */ + void +init_chartabsize_arg( + chartabsize_T *cts, + win_T *wp, + linenr_T lnum UNUSED, + colnr_T col, + char_u *line, + char_u *ptr) +{ + CLEAR_POINTER(cts); + cts->cts_win = wp; + cts->cts_vcol = col; + cts->cts_line = line; + cts->cts_ptr = ptr; +#ifdef FEAT_PROP_POPUP + if (lnum > 0 && !ignore_text_props) + { + char_u *prop_start; + int count; + + count = get_text_props(wp->w_buffer, lnum, &prop_start, FALSE); + cts->cts_text_prop_count = count; + if (count > 0) + { + // Make a copy of the properties, so that they are properly + // aligned. Make it twice as long for the sorting below. + cts->cts_text_props = ALLOC_MULT(textprop_T, count * 2); + if (cts->cts_text_props == NULL) + cts->cts_text_prop_count = 0; + else + { + int i; + + mch_memmove(cts->cts_text_props + count, prop_start, + count * sizeof(textprop_T)); + for (i = 0; i < count; ++i) + { + textprop_T *tp = cts->cts_text_props + i + count; + if (tp->tp_id < 0 + && text_prop_type_valid(wp->w_buffer, tp)) + { + cts->cts_has_prop_with_text = TRUE; + break; + } + } + if (!cts->cts_has_prop_with_text) + { + // won't use the text properties, free them + VIM_CLEAR(cts->cts_text_props); + cts->cts_text_prop_count = 0; + } + else + { + int *text_prop_idxs; + + // Need to sort the array to get any truncation right. + // Do the sorting in the second part of the array, then + // move the sorted props to the first part of the array. + text_prop_idxs = ALLOC_MULT(int, count); + if (text_prop_idxs != NULL) + { + for (i = 0; i < count; ++i) + text_prop_idxs[i] = i + count; + sort_text_props(curbuf, cts->cts_text_props, + text_prop_idxs, count); + // Here we want the reverse order. + for (i = 0; i < count; ++i) + cts->cts_text_props[count - i - 1] = + cts->cts_text_props[text_prop_idxs[i]]; + vim_free(text_prop_idxs); + } + } + } + } + } +#endif +} + +/* + * Free any allocated item in "cts". + */ + void +clear_chartabsize_arg(chartabsize_T *cts UNUSED) +{ +#ifdef FEAT_PROP_POPUP + if (cts->cts_text_prop_count > 0) + { + VIM_CLEAR(cts->cts_text_props); + cts->cts_text_prop_count = 0; + } +#endif +} + +/* + * Like chartabsize(), but also check for line breaks on the screen and text + * properties that insert text. + */ + int +lbr_chartabsize(chartabsize_T *cts) +{ +#if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP) + if (1 +# ifdef FEAT_LINEBREAK + && !curwin->w_p_lbr && *get_showbreak_value(curwin) == NUL + && !curwin->w_p_bri +# endif +# ifdef FEAT_PROP_POPUP + && !cts->cts_has_prop_with_text +#endif + ) + { +#endif + if (curwin->w_p_wrap) + return win_nolbr_chartabsize(cts, NULL); + RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, cts->cts_ptr, cts->cts_vcol) +#if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP) + } + return win_lbr_chartabsize(cts, NULL); +#endif +} + +/* + * Call lbr_chartabsize() and advance the pointer. + */ + int +lbr_chartabsize_adv(chartabsize_T *cts) +{ + int retval; + + retval = lbr_chartabsize(cts); + MB_PTR_ADV(cts->cts_ptr); + return retval; +} + +/* + * Return the screen size of the character indicated by "cts". + * "cts->cts_cur_text_width" is set to the extra size for a text property that + * inserts text. + * This function is used very often, keep it fast!!!! + * + * If "headp" not NULL, set *headp to the size of what we for 'showbreak' + * string at start of line. Warning: *headp is only set if it's a non-zero + * value, init to 0 before calling. + */ + int +win_lbr_chartabsize( + chartabsize_T *cts, + int *headp UNUSED) +{ + win_T *wp = cts->cts_win; +#if defined(FEAT_PROP_POPUP) || defined(FEAT_LINEBREAK) + char_u *line = cts->cts_line; // start of the line +#endif + char_u *s = cts->cts_ptr; + colnr_T vcol = cts->cts_vcol; +#ifdef FEAT_LINEBREAK + int c; + int size; + colnr_T col2; + colnr_T col_adj = 0; // vcol + screen size of tab + colnr_T colmax; + int added; + int mb_added = 0; + int numberextra; + char_u *ps; + int tab_corr = (*s == TAB); + int n; + char_u *sbr; + int no_sbr = FALSE; +#endif + +#if defined(FEAT_PROP_POPUP) + cts->cts_cur_text_width = 0; + cts->cts_first_char = 0; +#endif + +#if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP) + /* + * No 'linebreak', 'showbreak', 'breakindent' and text properties that + * insert text: return quickly. + */ + if (1 +# ifdef FEAT_LINEBREAK + && !wp->w_p_lbr && !wp->w_p_bri && *get_showbreak_value(wp) == NUL +# endif +# ifdef FEAT_PROP_POPUP + && !cts->cts_has_prop_with_text +# endif + ) +#endif + { + if (wp->w_p_wrap) + return win_nolbr_chartabsize(cts, headp); + RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, s, vcol) + } + +#if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP) + /* + * First get the normal size, without 'linebreak' or text properties + */ + size = win_chartabsize(wp, s, vcol); + if (*s == NUL) + size = 0; // NUL is not displayed + +# ifdef FEAT_PROP_POPUP + if (cts->cts_has_prop_with_text) + { + int tab_size = size; + int charlen = *s == NUL ? 1 : mb_ptr2len(s); + int i; + int col = (int)(s - line); + garray_T *gap = &wp->w_buffer->b_textprop_text; + + // The "$" for 'list' mode will go between the EOL and + // the text prop, account for that. + if (wp->w_p_list && wp->w_lcs_chars.eol != NUL) + ++vcol; + + for (i = 0; i < cts->cts_text_prop_count; ++i) + { + textprop_T *tp = cts->cts_text_props + i; + int col_off = win_col_off(wp); + + // Watch out for the text being deleted. "cts_text_props" is a + // copy, the text prop may actually have been removed from the line. + if (tp->tp_id < 0 + && ((tp->tp_col - 1 >= col + && tp->tp_col - 1 < col + charlen) + || (tp->tp_col == MAXCOL + && ((tp->tp_flags & TP_FLAG_ALIGN_ABOVE) + ? col == 0 + : (s[0] == NUL || s[charlen] == NUL) + && cts->cts_with_trailing))) + && -tp->tp_id - 1 < gap->ga_len) + { + char_u *p = ((char_u **)gap->ga_data)[-tp->tp_id - 1]; + + if (p != NULL) + { + int cells; + + if (tp->tp_col == MAXCOL) + { + int n_extra = (int)STRLEN(p); + + cells = text_prop_position(wp, tp, vcol, + (vcol + size) % (wp->w_width - col_off) + col_off, + &n_extra, &p, NULL, NULL, FALSE); +#ifdef FEAT_LINEBREAK + no_sbr = TRUE; // don't use 'showbreak' now +#endif + } + else + cells = vim_strsize(p); + cts->cts_cur_text_width += cells; + if (tp->tp_flags & TP_FLAG_ALIGN_ABOVE) + cts->cts_first_char += cells; + cts->cts_start_incl = tp->tp_flags & TP_FLAG_START_INCL; + size += cells; + if (*s == TAB) + { + // tab size changes because of the inserted text + size -= tab_size; + tab_size = win_chartabsize(wp, s, vcol + size); + size += tab_size; + } + if (tp->tp_col == MAXCOL && (tp->tp_flags + & (TP_FLAG_ALIGN_ABOVE | TP_FLAG_ALIGN_BELOW))) + // count extra line for property above/below + ++cts->cts_prop_lines; + } + } + if (tp->tp_col != MAXCOL && tp->tp_col - 1 > col) + break; + } + if (wp->w_p_list && wp->w_lcs_chars.eol != NUL) + --vcol; + } +# endif + +# ifdef FEAT_LINEBREAK + c = *s; + if (tab_corr) + col_adj = size - 1; + + /* + * If 'linebreak' set check at a blank before a non-blank if the line + * needs a break here + */ + if (wp->w_p_lbr + && VIM_ISBREAK(c) + && !VIM_ISBREAK((int)s[1]) + && wp->w_p_wrap + && wp->w_width != 0) + { + /* + * Count all characters from first non-blank after a blank up to next + * non-blank after a blank. + */ + numberextra = win_col_off(wp); + col2 = vcol; + colmax = (colnr_T)(wp->w_width - numberextra - col_adj); + if (vcol >= colmax) + { + colmax += col_adj; + n = colmax + win_col_off2(wp); + if (n > 0) + colmax += (((vcol - colmax) / n) + 1) * n - col_adj; + } + + for (;;) + { + ps = s; + MB_PTR_ADV(s); + c = *s; + if (!(c != NUL + && (VIM_ISBREAK(c) + || (!VIM_ISBREAK(c) + && (col2 == vcol || !VIM_ISBREAK((int)*ps)))))) + break; + + col2 += win_chartabsize(wp, s, col2); + if (col2 >= colmax) // doesn't fit + { + size = colmax - vcol + col_adj; + break; + } + } + } + else if (has_mbyte && size == 2 && MB_BYTE2LEN(*s) > 1 + && wp->w_p_wrap && in_win_border(wp, vcol)) + { + ++size; // Count the ">" in the last column. + mb_added = 1; + } + + /* + * May have to add something for 'breakindent' and/or 'showbreak' + * string at start of line. + * Set *headp to the size of what we add. + * Do not use 'showbreak' at the NUL after the text. + */ + added = 0; + sbr = (c == NUL || no_sbr) ? empty_option : get_showbreak_value(wp); + if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0) + { + colnr_T sbrlen = 0; + int numberwidth = win_col_off(wp); + + numberextra = numberwidth; + vcol += numberextra + mb_added; +#ifdef FEAT_PROP_POPUP + vcol -= wp->w_virtcol_first_char; +#endif + if (vcol >= (colnr_T)wp->w_width) + { + vcol -= wp->w_width; + numberextra = wp->w_width - (numberextra - win_col_off2(wp)); + if (vcol >= numberextra && numberextra > 0) + vcol %= numberextra; + if (*sbr != NUL) + { + sbrlen = (colnr_T)MB_CHARLEN(sbr); + if (vcol >= sbrlen) + vcol -= sbrlen; + } + if (vcol >= numberextra && numberextra > 0) + vcol = vcol % numberextra; + else if (vcol > 0 && numberextra > 0) + vcol += numberwidth - win_col_off2(wp); + + numberwidth -= win_col_off2(wp); + } + if (vcol == 0 || vcol + size + sbrlen > (colnr_T)wp->w_width) + { + added = 0; + if (*sbr != NUL) + { + if (size + sbrlen + numberwidth > (colnr_T)wp->w_width) + { + // calculate effective window width + int width = (colnr_T)wp->w_width - sbrlen - numberwidth; + int prev_width = vcol + ? ((colnr_T)wp->w_width - (sbrlen + vcol)) : 0; + + if (width <= 0) + width = (colnr_T)1; + added += ((size - prev_width) / width) * vim_strsize(sbr); + if ((size - prev_width) % width) + // wrapped, add another length of 'sbr' + added += vim_strsize(sbr); + } + else + added += vim_strsize(sbr); + } + if (wp->w_p_bri) + added += get_breakindent_win(wp, line); + + size += added; + if (vcol != 0) + added = 0; + } + } + if (headp != NULL) + *headp = added + mb_added; + return size; +# endif +#endif +} + +/* + * Like win_lbr_chartabsize(), except that we know 'linebreak' is off, 'wrap' + * is on and there are no properties that insert text. This means we need to + * check for a double-byte character that doesn't fit at the end of the screen + * line. + * Only uses "cts_win", "cts_ptr" and "cts_vcol" from "cts". + */ + static int +win_nolbr_chartabsize( + chartabsize_T *cts, + int *headp) +{ + win_T *wp = cts->cts_win; + char_u *s = cts->cts_ptr; + colnr_T col = cts->cts_vcol; + int n; + + if (*s == TAB && (!wp->w_p_list || wp->w_lcs_chars.tab1)) + { +# ifdef FEAT_VARTABS + return tabstop_padding(col, wp->w_buffer->b_p_ts, + wp->w_buffer->b_p_vts_array); +# else + n = wp->w_buffer->b_p_ts; + return (int)(n - (col % n)); +# endif + } + n = ptr2cells(s); + // Add one cell for a double-width character in the last column of the + // window, displayed with a ">". + if (n == 2 && MB_BYTE2LEN(*s) > 1 && in_win_border(wp, col)) + { + if (headp != NULL) + *headp = 1; + return 3; + } + return n; +} + +/* + * Return TRUE if virtual column "vcol" is in the rightmost column of window + * "wp". + */ + static int +in_win_border(win_T *wp, colnr_T vcol) +{ + int width1; // width of first line (after line number) + int width2; // width of further lines + + if (wp->w_width == 0) // there is no border + return FALSE; + width1 = wp->w_width - win_col_off(wp); + if ((int)vcol < width1 - 1) + return FALSE; + if ((int)vcol == width1 - 1) + return TRUE; + width2 = width1 + win_col_off2(wp); + if (width2 <= 0) + return FALSE; + return ((vcol - width1) % width2 == width2 - 1); +} + +/* + * Get virtual column number of pos. + * start: on the first position of this character (TAB, ctrl) + * cursor: where the cursor is on this character (first char, except for TAB) + * end: on the last position of this character (TAB, ctrl) + * + * This is used very often, keep it fast! + */ + void +getvcol( + win_T *wp, + pos_T *pos, + colnr_T *start, + colnr_T *cursor, + colnr_T *end) +{ + colnr_T vcol; + char_u *ptr; // points to current char + char_u *posptr; // points to char at pos->col + char_u *line; // start of the line + int incr; + int head; +#ifdef FEAT_VARTABS + int *vts = wp->w_buffer->b_p_vts_array; +#endif + int ts = wp->w_buffer->b_p_ts; + int c; + chartabsize_T cts; +#ifdef FEAT_PROP_POPUP + int on_NUL = FALSE; +#endif + + vcol = 0; + line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE); + if (pos->col == MAXCOL) + posptr = NULL; // continue until the NUL + else + { + colnr_T i; + + // In a few cases the position can be beyond the end of the line. + for (i = 0; i < pos->col; ++i) + if (ptr[i] == NUL) + { + pos->col = i; + break; + } + posptr = ptr + pos->col; + if (has_mbyte) + // always start on the first byte + posptr -= (*mb_head_off)(line, posptr); + } + + init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line); + + /* + * This function is used very often, do some speed optimizations. + * When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set + * and there are no text properties with "text" use a simple loop. + * Also use this when 'list' is set but tabs take their normal size. + */ + if ((!wp->w_p_list || wp->w_lcs_chars.tab1 != NUL) +#ifdef FEAT_LINEBREAK + && !wp->w_p_lbr && *get_showbreak_value(wp) == NUL && !wp->w_p_bri +#endif +#ifdef FEAT_PROP_POPUP + && !cts.cts_has_prop_with_text +#endif + ) + { + for (;;) + { + head = 0; + c = *ptr; + // make sure we don't go past the end of the line + if (c == NUL) + { + incr = 1; // NUL at end of line only takes one column + break; + } + // A tab gets expanded, depending on the current column + if (c == TAB) +#ifdef FEAT_VARTABS + incr = tabstop_padding(vcol, ts, vts); +#else + incr = ts - (vcol % ts); +#endif + else + { + if (has_mbyte) + { + // For utf-8, if the byte is >= 0x80, need to look at + // further bytes to find the cell width. + if (enc_utf8 && c >= 0x80) + incr = utf_ptr2cells(ptr); + else + incr = g_chartab[c] & CT_CELL_MASK; + + // If a double-cell char doesn't fit at the end of a line + // it wraps to the next line, it's like this char is three + // cells wide. + if (incr == 2 && wp->w_p_wrap && MB_BYTE2LEN(*ptr) > 1 + && in_win_border(wp, vcol)) + { + ++incr; + head = 1; + } + } + else + incr = g_chartab[c] & CT_CELL_MASK; + } + + if (posptr != NULL && ptr >= posptr) // character at pos->col + break; + + vcol += incr; + MB_PTR_ADV(ptr); + } + } + else + { + for (;;) + { + // A tab gets expanded, depending on the current column. + // Other things also take up space. + head = 0; + incr = win_lbr_chartabsize(&cts, &head); + // make sure we don't go past the end of the line + if (*cts.cts_ptr == NUL) + { + incr = 1; // NUL at end of line only takes one column +#ifdef FEAT_PROP_POPUP + if (cts.cts_cur_text_width > 0) + incr = cts.cts_cur_text_width; + on_NUL = TRUE; +#endif + break; + } +#ifdef FEAT_PROP_POPUP + if (cursor == &wp->w_virtcol && cts.cts_ptr == cts.cts_line) + // do not count the virtual text above for w_curswant + wp->w_virtcol_first_char = cts.cts_first_char; +#endif + + if (posptr != NULL && cts.cts_ptr >= posptr) + // character at pos->col + break; + + cts.cts_vcol += incr; + MB_PTR_ADV(cts.cts_ptr); + } + vcol = cts.cts_vcol; + ptr = cts.cts_ptr; + } + clear_chartabsize_arg(&cts); + + if (start != NULL) + *start = vcol + head; + if (end != NULL) + *end = vcol + incr - 1; + if (cursor != NULL) + { + if (*ptr == TAB + && (State & MODE_NORMAL) + && !wp->w_p_list + && !virtual_active() + && !(VIsual_active + && (*p_sel == 'e' || LTOREQ_POS(*pos, VIsual))) + ) + *cursor = vcol + incr - 1; // cursor at end + else + { +#ifdef FEAT_PROP_POPUP + // in Insert mode, if "start_incl" is true the text gets inserted + // after the virtual text, thus add its width + if (((State & MODE_INSERT) == 0 || cts.cts_start_incl) && !on_NUL) + // cursor is after inserted text, unless on the NUL + vcol += cts.cts_cur_text_width; + else + // insertion also happens after the "above" virtual text + vcol += cts.cts_first_char; +#endif + *cursor = vcol + head; // cursor at start + } + } +} + +/* + * Get virtual cursor column in the current window, pretending 'list' is off. + */ + colnr_T +getvcol_nolist(pos_T *posp) +{ + int list_save = curwin->w_p_list; + colnr_T vcol; + + curwin->w_p_list = FALSE; + if (posp->coladd) + getvvcol(curwin, posp, NULL, &vcol, NULL); + else + getvcol(curwin, posp, NULL, &vcol, NULL); + curwin->w_p_list = list_save; + return vcol; +} + +/* + * Get virtual column in virtual mode. + */ + void +getvvcol( + win_T *wp, + pos_T *pos, + colnr_T *start, + colnr_T *cursor, + colnr_T *end) +{ + colnr_T col; + colnr_T coladd; + colnr_T endadd; + char_u *ptr; + + if (virtual_active()) + { + // For virtual mode, only want one value + getvcol(wp, pos, &col, NULL, NULL); + + coladd = pos->coladd; + endadd = 0; + // Cannot put the cursor on part of a wide character. + ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE); + if (pos->col < (colnr_T)STRLEN(ptr)) + { + int c = (*mb_ptr2char)(ptr + pos->col); + + if (c != TAB && vim_isprintc(c)) + { + endadd = (colnr_T)(char2cells(c) - 1); + if (coladd > endadd) // past end of line + endadd = 0; + else + coladd = 0; + } + } + col += coladd; + if (start != NULL) + *start = col; + if (cursor != NULL) + *cursor = col; + if (end != NULL) + *end = col + endadd; + } + else + getvcol(wp, pos, start, cursor, end); +} + +/* + * Get the leftmost and rightmost virtual column of pos1 and pos2. + * Used for Visual block mode. + */ + void +getvcols( + win_T *wp, + pos_T *pos1, + pos_T *pos2, + colnr_T *left, + colnr_T *right) +{ + colnr_T from1, from2, to1, to2; + + if (LT_POSP(pos1, pos2)) + { + getvvcol(wp, pos1, &from1, NULL, &to1); + getvvcol(wp, pos2, &from2, NULL, &to2); + } + else + { + getvvcol(wp, pos2, &from1, NULL, &to1); + getvvcol(wp, pos1, &from2, NULL, &to2); + } + if (from2 < from1) + *left = from2; + else + *left = from1; + if (to2 > to1) + { + if (*p_sel == 'e' && from2 - 1 >= to1) + *right = from2 - 1; + else + *right = to2; + } + else + *right = to1; +} + +/* + * Skip over ' ' and '\t'. + */ + char_u * +skipwhite(char_u *q) +{ + char_u *p = q; + + while (VIM_ISWHITE(*p)) + ++p; + return p; +} + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * skip over ' ', '\t' and '\n'. + */ + char_u * +skipwhite_and_nl(char_u *q) +{ + char_u *p = q; + + while (VIM_ISWHITE(*p) || *p == NL) + ++p; + return p; +} +#endif + +/* + * getwhitecols: return the number of whitespace + * columns (bytes) at the start of a given line + */ + int +getwhitecols_curline(void) +{ + return getwhitecols(ml_get_curline()); +} + + int +getwhitecols(char_u *p) +{ + return skipwhite(p) - p; +} + +/* + * skip over digits + */ + char_u * +skipdigits(char_u *q) +{ + char_u *p = q; + + while (VIM_ISDIGIT(*p)) // skip to next non-digit + ++p; + return p; +} + +#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL) || defined(PROTO) +/* + * skip over binary digits + */ + char_u * +skipbin(char_u *q) +{ + char_u *p = q; + + while (vim_isbdigit(*p)) // skip to next non-digit + ++p; + return p; +} + +/* + * skip over digits and hex characters + */ + char_u * +skiphex(char_u *q) +{ + char_u *p = q; + + while (vim_isxdigit(*p)) // skip to next non-digit + ++p; + return p; +} +#endif + +/* + * skip to bin digit (or NUL after the string) + */ + char_u * +skiptobin(char_u *q) +{ + char_u *p = q; + + while (*p != NUL && !vim_isbdigit(*p)) // skip to next digit + ++p; + return p; +} + +/* + * skip to digit (or NUL after the string) + */ + char_u * +skiptodigit(char_u *q) +{ + char_u *p = q; + + while (*p != NUL && !VIM_ISDIGIT(*p)) // skip to next digit + ++p; + return p; +} + +/* + * skip to hex character (or NUL after the string) + */ + char_u * +skiptohex(char_u *q) +{ + char_u *p = q; + + while (*p != NUL && !vim_isxdigit(*p)) // skip to next digit + ++p; + return p; +} + +/* + * Variant of isdigit() that can handle characters > 0x100. + * We don't use isdigit() here, because on some systems it also considers + * superscript 1 to be a digit. + * Use the VIM_ISDIGIT() macro for simple arguments. + */ + int +vim_isdigit(int c) +{ + return (c >= '0' && c <= '9'); +} + +/* + * Variant of isxdigit() that can handle characters > 0x100. + * We don't use isxdigit() here, because on some systems it also considers + * superscript 1 to be a digit. + */ + int +vim_isxdigit(int c) +{ + return (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F'); +} + +/* + * Corollary of vim_isdigit and vim_isxdigit() that can handle + * characters > 0x100. + */ + int +vim_isbdigit(int c) +{ + return (c == '0' || c == '1'); +} + + static int +vim_isodigit(int c) +{ + return (c >= '0' && c <= '7'); +} + +/* + * Vim's own character class functions. These exist because many library + * islower()/toupper() etc. do not work properly: they crash when used with + * invalid values or can't handle latin1 when the locale is C. + * Speed is most important here. + */ +#define LATIN1LOWER 'l' +#define LATIN1UPPER 'U' + +static char_u latin1flags[257] = " UUUUUUUUUUUUUUUUUUUUUUUUUU llllllllllllllllllllllllll UUUUUUUUUUUUUUUUUUUUUUU UUUUUUUllllllllllllllllllllllll llllllll"; +static char_u latin1upper[257] = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xf7\xd8\xd9\xda\xdb\xdc\xdd\xde\xff"; +static char_u latin1lower[257] = " !\"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xd7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; + + int +vim_islower(int c) +{ + if (c <= '@') + return FALSE; + if (c >= 0x80) + { + if (enc_utf8) + return utf_islower(c); + if (c >= 0x100) + { +#ifdef HAVE_ISWLOWER + if (has_mbyte) + return iswlower(c); +#endif + // islower() can't handle these chars and may crash + return FALSE; + } + if (enc_latin1like) + return (latin1flags[c] & LATIN1LOWER) == LATIN1LOWER; + } + return islower(c); +} + + int +vim_isupper(int c) +{ + if (c <= '@') + return FALSE; + if (c >= 0x80) + { + if (enc_utf8) + return utf_isupper(c); + if (c >= 0x100) + { +#ifdef HAVE_ISWUPPER + if (has_mbyte) + return iswupper(c); +#endif + // islower() can't handle these chars and may crash + return FALSE; + } + if (enc_latin1like) + return (latin1flags[c] & LATIN1UPPER) == LATIN1UPPER; + } + return isupper(c); +} + + int +vim_isalpha(int c) +{ + return vim_islower(c) || vim_isupper(c); +} + + int +vim_toupper(int c) +{ + if (c <= '@') + return c; + if (c >= 0x80 || !(cmp_flags & CMP_KEEPASCII)) + { + if (enc_utf8) + return utf_toupper(c); + if (c >= 0x100) + { +#ifdef HAVE_TOWUPPER + if (has_mbyte) + return towupper(c); +#endif + // toupper() can't handle these chars and may crash + return c; + } + if (enc_latin1like) + return latin1upper[c]; + } + if (c < 0x80 && (cmp_flags & CMP_KEEPASCII)) + return TOUPPER_ASC(c); + return TOUPPER_LOC(c); +} + + int +vim_tolower(int c) +{ + if (c <= '@') + return c; + if (c >= 0x80 || !(cmp_flags & CMP_KEEPASCII)) + { + if (enc_utf8) + return utf_tolower(c); + if (c >= 0x100) + { +#ifdef HAVE_TOWLOWER + if (has_mbyte) + return towlower(c); +#endif + // tolower() can't handle these chars and may crash + return c; + } + if (enc_latin1like) + return latin1lower[c]; + } + if (c < 0x80 && (cmp_flags & CMP_KEEPASCII)) + return TOLOWER_ASC(c); + return TOLOWER_LOC(c); +} + +/* + * skiptowhite: skip over text until ' ' or '\t' or NUL. + */ + char_u * +skiptowhite(char_u *p) +{ + while (*p != ' ' && *p != '\t' && *p != NUL) + ++p; + return p; +} + +/* + * skiptowhite_esc: Like skiptowhite(), but also skip escaped chars + */ + char_u * +skiptowhite_esc(char_u *p) +{ + while (*p != ' ' && *p != '\t' && *p != NUL) + { + if ((*p == '\\' || *p == Ctrl_V) && *(p + 1) != NUL) + ++p; + ++p; + } + return p; +} + +/* + * Get a number from a string and skip over it. + * Note: the argument is a pointer to a char_u pointer! + */ + long +getdigits(char_u **pp) +{ + char_u *p; + long retval; + + p = *pp; + retval = atol((char *)p); + if (*p == '-') // skip negative sign + ++p; + p = skipdigits(p); // skip to next non-digit + *pp = p; + return retval; +} + +/* + * Like getdigits() but allow for embedded single quotes. + */ + long +getdigits_quoted(char_u **pp) +{ + char_u *p = *pp; + long retval = 0; + + if (*p == '-') + ++p; + while (VIM_ISDIGIT(*p)) + { + if (retval >= LONG_MAX / 10 - 10) + retval = LONG_MAX; + else + retval = retval * 10 - '0' + *p; + ++p; + if (in_vim9script() && *p == '\'' && VIM_ISDIGIT(p[1])) + ++p; + } + if (**pp == '-') + { + if (retval == LONG_MAX) + retval = LONG_MIN; + else + retval = -retval; + } + *pp = p; + return retval; +} + +/* + * Return TRUE if "lbuf" is empty or only contains blanks. + */ + int +vim_isblankline(char_u *lbuf) +{ + char_u *p; + + p = skipwhite(lbuf); + return (*p == NUL || *p == '\r' || *p == '\n'); +} + +/* + * Convert a string into a long and/or unsigned long, taking care of + * hexadecimal, octal, and binary numbers. Accepts a '-' sign. + * If "prep" is not NULL, returns a flag to indicate the type of the number: + * 0 decimal + * '0' octal + * 'O' octal + * 'o' octal + * 'B' bin + * 'b' bin + * 'X' hex + * 'x' hex + * If "len" is not NULL, the length of the number in characters is returned. + * If "nptr" is not NULL, the signed result is returned in it. + * If "unptr" is not NULL, the unsigned result is returned in it. + * If "what" contains STR2NR_BIN recognize binary numbers + * If "what" contains STR2NR_OCT recognize octal numbers + * If "what" contains STR2NR_HEX recognize hex numbers + * If "what" contains STR2NR_FORCE always assume bin/oct/hex. + * If "what" contains STR2NR_QUOTE ignore embedded single quotes + * If maxlen > 0, check at a maximum maxlen chars. + * If strict is TRUE, check the number strictly. return *len = 0 if fail. + */ + void +vim_str2nr( + char_u *start, + int *prep, // return: type of number 0 = decimal, 'x' + // or 'X' is hex, '0', 'o' or 'O' is octal, + // 'b' or 'B' is bin + int *len, // return: detected length of number + int what, // what numbers to recognize + varnumber_T *nptr, // return: signed result + uvarnumber_T *unptr, // return: unsigned result + int maxlen, // max length of string to check + int strict) // check strictly +{ + char_u *ptr = start; + int pre = 0; // default is decimal + int negative = FALSE; + uvarnumber_T un = 0; + int n; + + if (len != NULL) + *len = 0; + + if (ptr[0] == '-') + { + negative = TRUE; + ++ptr; + } + + // Recognize hex, octal, and bin. + if (ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9' + && (maxlen == 0 || maxlen > 1)) + { + pre = ptr[1]; + if ((what & STR2NR_HEX) + && (pre == 'X' || pre == 'x') && vim_isxdigit(ptr[2]) + && (maxlen == 0 || maxlen > 2)) + // hexadecimal + ptr += 2; + else if ((what & STR2NR_BIN) + && (pre == 'B' || pre == 'b') && vim_isbdigit(ptr[2]) + && (maxlen == 0 || maxlen > 2)) + // binary + ptr += 2; + else if ((what & STR2NR_OOCT) + && (pre == 'O' || pre == 'o') && vim_isodigit(ptr[2]) + && (maxlen == 0 || maxlen > 2)) + // octal with prefix "0o" + ptr += 2; + else + { + // decimal or octal, default is decimal + pre = 0; + if (what & STR2NR_OCT) + { + // Don't interpret "0", "08" or "0129" as octal. + for (n = 1; n != maxlen && VIM_ISDIGIT(ptr[n]); ++n) + { + if (ptr[n] > '7') + { + pre = 0; // can't be octal + break; + } + pre = '0'; // assume octal + } + } + } + } + + // Do the conversion manually to avoid sscanf() quirks. + n = 1; + if (pre == 'B' || pre == 'b' + || ((what & STR2NR_BIN) && (what & STR2NR_FORCE))) + { + // bin + if (pre != 0) + n += 2; // skip over "0b" + while ('0' <= *ptr && *ptr <= '1') + { + // avoid ubsan error for overflow + if (un <= UVARNUM_MAX / 2) + un = 2 * un + (uvarnumber_T)(*ptr - '0'); + else + un = UVARNUM_MAX; + ++ptr; + if (n++ == maxlen) + break; + if ((what & STR2NR_QUOTE) && *ptr == '\'' + && '0' <= ptr[1] && ptr[1] <= '1') + { + ++ptr; + if (n++ == maxlen) + break; + } + } + } + else if (pre == 'O' || pre == 'o' || + pre == '0' || ((what & STR2NR_OCT) && (what & STR2NR_FORCE))) + { + // octal + if (pre != 0 && pre != '0') + n += 2; // skip over "0o" + while ('0' <= *ptr && *ptr <= '7') + { + // avoid ubsan error for overflow + if (un <= UVARNUM_MAX / 8) + un = 8 * un + (uvarnumber_T)(*ptr - '0'); + else + un = UVARNUM_MAX; + ++ptr; + if (n++ == maxlen) + break; + if ((what & STR2NR_QUOTE) && *ptr == '\'' + && '0' <= ptr[1] && ptr[1] <= '7') + { + ++ptr; + if (n++ == maxlen) + break; + } + } + } + else if (pre != 0 || ((what & STR2NR_HEX) && (what & STR2NR_FORCE))) + { + // hex + if (pre != 0) + n += 2; // skip over "0x" + while (vim_isxdigit(*ptr)) + { + // avoid ubsan error for overflow + if (un <= UVARNUM_MAX / 16) + un = 16 * un + (uvarnumber_T)hex2nr(*ptr); + else + un = UVARNUM_MAX; + ++ptr; + if (n++ == maxlen) + break; + if ((what & STR2NR_QUOTE) && *ptr == '\'' && vim_isxdigit(ptr[1])) + { + ++ptr; + if (n++ == maxlen) + break; + } + } + } + else + { + // decimal + while (VIM_ISDIGIT(*ptr)) + { + uvarnumber_T digit = (uvarnumber_T)(*ptr - '0'); + + // avoid ubsan error for overflow + if (un < UVARNUM_MAX / 10 + || (un == UVARNUM_MAX / 10 && digit <= UVARNUM_MAX % 10)) + un = 10 * un + digit; + else + un = UVARNUM_MAX; + ++ptr; + if (n++ == maxlen) + break; + if ((what & STR2NR_QUOTE) && *ptr == '\'' && VIM_ISDIGIT(ptr[1])) + { + ++ptr; + if (n++ == maxlen) + break; + } + } + } + + // Check for an alphanumeric character immediately following, that is + // most likely a typo. + if (strict && n - 1 != maxlen && ASCII_ISALNUM(*ptr)) + return; + + if (prep != NULL) + *prep = pre; + if (len != NULL) + *len = (int)(ptr - start); + if (nptr != NULL) + { + if (negative) // account for leading '-' for decimal numbers + { + // avoid ubsan error for overflow + if (un > VARNUM_MAX) + *nptr = VARNUM_MIN; + else + *nptr = -(varnumber_T)un; + } + else + { + // prevent a large unsigned number to become negative + if (un > VARNUM_MAX) + un = VARNUM_MAX; + *nptr = (varnumber_T)un; + } + } + if (unptr != NULL) + *unptr = un; +} + +/* + * Return the value of a single hex character. + * Only valid when the argument is '0' - '9', 'A' - 'F' or 'a' - 'f'. + */ + int +hex2nr(int c) +{ + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return c - '0'; +} + +/* + * Convert two hex characters to a byte. + * Return -1 if one of the characters is not hex. + */ + int +hexhex2nr(char_u *p) +{ + if (!vim_isxdigit(p[0]) || !vim_isxdigit(p[1])) + return -1; + return (hex2nr(p[0]) << 4) + hex2nr(p[1]); +} + +/* + * Return TRUE if "str" starts with a backslash that should be removed. + * For MS-DOS, MSWIN and OS/2 this is only done when the character after the + * backslash is not a normal file name character. + * '$' is a valid file name character, we don't remove the backslash before + * it. This means it is not possible to use an environment variable after a + * backslash. "C:\$VIM\doc" is taken literally, only "$VIM\doc" works. + * Although "\ name" is valid, the backslash in "Program\ files" must be + * removed. Assume a file name doesn't start with a space. + * For multi-byte names, never remove a backslash before a non-ascii + * character, assume that all multi-byte characters are valid file name + * characters. + */ + int +rem_backslash(char_u *str) +{ +#ifdef BACKSLASH_IN_FILENAME + return (str[0] == '\\' + && str[1] < 0x80 + && (str[1] == ' ' + || (str[1] != NUL + && str[1] != '*' + && str[1] != '?' + && !vim_isfilec(str[1])))); +#else + return (str[0] == '\\' && str[1] != NUL); +#endif +} + +/* + * Halve the number of backslashes in a file name argument. + * For MS-DOS we only do this if the character after the backslash + * is not a normal file character. + */ + void +backslash_halve(char_u *p) +{ + for ( ; *p; ++p) + if (rem_backslash(p)) + STRMOVE(p, p + 1); +} + +/* + * backslash_halve() plus save the result in allocated memory. + * However, returns "p" when out of memory. + */ + char_u * +backslash_halve_save(char_u *p) +{ + char_u *res; + + res = vim_strsave(p); + if (res == NULL) + return p; + backslash_halve(res); + return res; +} diff --git a/src/cindent.c b/src/cindent.c new file mode 100644 index 0000000..e8e255f --- /dev/null +++ b/src/cindent.c @@ -0,0 +1,4179 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * cindent.c: C indentation related functions + * + * Many of C-indenting functions originally come from Eric Fischer. + * + * Below "XXX" means that this function may unlock the current line. + */ + +#include "vim.h" + +// values for the "lookfor" state +#define LOOKFOR_INITIAL 0 +#define LOOKFOR_IF 1 +#define LOOKFOR_DO 2 +#define LOOKFOR_CASE 3 +#define LOOKFOR_ANY 4 +#define LOOKFOR_TERM 5 +#define LOOKFOR_UNTERM 6 +#define LOOKFOR_SCOPEDECL 7 +#define LOOKFOR_NOBREAK 8 +#define LOOKFOR_CPP_BASECLASS 9 +#define LOOKFOR_ENUM_OR_INIT 10 +#define LOOKFOR_JS_KEY 11 +#define LOOKFOR_COMMA 12 + +/* + * Return TRUE if the string "line" starts with a word from 'cinwords'. + */ + int +cin_is_cinword(char_u *line) +{ + char_u *cinw; + char_u *cinw_buf; + int cinw_len; + int retval = FALSE; + int len; + + cinw_len = (int)STRLEN(curbuf->b_p_cinw) + 1; + cinw_buf = alloc(cinw_len); + if (cinw_buf == NULL) + return FALSE; + + line = skipwhite(line); + for (cinw = curbuf->b_p_cinw; *cinw; ) + { + len = copy_option_part(&cinw, cinw_buf, cinw_len, ","); + if (STRNCMP(line, cinw_buf, len) == 0 + && (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1]))) + { + retval = TRUE; + break; + } + } + vim_free(cinw_buf); + return retval; +} + +/* + * Skip to the end of a "string" and a 'c' character. + * If there is no string or character, return argument unmodified. + */ + static char_u * +skip_string(char_u *p) +{ + int i; + + // We loop, because strings may be concatenated: "date""time". + for ( ; ; ++p) + { + if (p[0] == '\'') // 'c' or '\n' or '\000' + { + if (p[1] == NUL) // ' at end of line + break; + i = 2; + if (p[1] == '\\' && p[2] != NUL) // '\n' or '\000' + { + ++i; + while (vim_isdigit(p[i - 1])) // '\000' + ++i; + } + if (p[i - 1] != NUL && p[i] == '\'') // check for trailing ' + { + p += i; + continue; + } + } + else if (p[0] == '"') // start of string + { + for (++p; p[0]; ++p) + { + if (p[0] == '\\' && p[1] != NUL) + ++p; + else if (p[0] == '"') // end of string + break; + } + if (p[0] == '"') + continue; // continue for another string + } + else if (p[0] == 'R' && p[1] == '"') + { + // Raw string: R"[delim](...)[delim]" + char_u *delim = p + 2; + char_u *paren = vim_strchr(delim, '('); + + if (paren != NULL) + { + size_t delim_len = paren - delim; + + for (p += 3; *p; ++p) + if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0 + && p[delim_len + 1] == '"') + { + p += delim_len + 1; + break; + } + if (p[0] == '"') + continue; // continue for another string + } + } + break; // no string found + } + if (!*p) + --p; // backup from NUL + return p; +} + +/* + * Return TRUE if "line[col]" is inside a C string. + */ + int +is_pos_in_string(char_u *line, colnr_T col) +{ + char_u *p; + + for (p = line; *p && (colnr_T)(p - line) < col; ++p) + p = skip_string(p); + return !((colnr_T)(p - line) <= col); +} + +/* + * Find the start of a comment, not knowing if we are in a comment right now. + * Search starts at w_cursor.lnum and goes backwards. + * Return NULL when not inside a comment. + */ + static pos_T * +ind_find_start_comment(void) // XXX +{ + return find_start_comment(curbuf->b_ind_maxcomment); +} + + pos_T * +find_start_comment(int ind_maxcomment) // XXX +{ + pos_T *pos; + int cur_maxcomment = ind_maxcomment; + + for (;;) + { + pos = findmatchlimit(NULL, '*', FM_BACKWARD, cur_maxcomment); + if (pos == NULL) + break; + + // Check if the comment start we found is inside a string. + // If it is then restrict the search to below this line and try again. + if (!is_pos_in_string(ml_get(pos->lnum), pos->col)) + break; + cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1; + if (cur_maxcomment <= 0) + { + pos = NULL; + break; + } + } + return pos; +} + +/* + * Find the start of a raw string, not knowing if we are in one right now. + * Search starts at w_cursor.lnum and goes backwards. + * Return NULL when not inside a raw string. + */ + static pos_T * +find_start_rawstring(int ind_maxcomment) // XXX +{ + pos_T *pos; + int cur_maxcomment = ind_maxcomment; + + for (;;) + { + pos = findmatchlimit(NULL, 'R', FM_BACKWARD, cur_maxcomment); + if (pos == NULL) + break; + + // Check if the raw string start we found is inside a string. + // If it is then restrict the search to below this line and try again. + if (!is_pos_in_string(ml_get(pos->lnum), pos->col)) + break; + cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1; + if (cur_maxcomment <= 0) + { + pos = NULL; + break; + } + } + return pos; +} + +/* + * Find the start of a comment or raw string, not knowing if we are in a + * comment or raw string right now. + * Search starts at w_cursor.lnum and goes backwards. + * If is_raw is given and returns start of raw_string, sets it to true. + * Return NULL when not inside a comment or raw string. + * "CORS" -> Comment Or Raw String + */ + static pos_T * +ind_find_start_CORS(linenr_T *is_raw) // XXX +{ + static pos_T comment_pos_copy; + pos_T *comment_pos; + pos_T *rs_pos; + + comment_pos = find_start_comment(curbuf->b_ind_maxcomment); + if (comment_pos != NULL) + { + // Need to make a copy of the static pos in findmatchlimit(), + // calling find_start_rawstring() may change it. + comment_pos_copy = *comment_pos; + comment_pos = &comment_pos_copy; + } + rs_pos = find_start_rawstring(curbuf->b_ind_maxcomment); + + // If comment_pos is before rs_pos the raw string is inside the comment. + // If rs_pos is before comment_pos the comment is inside the raw string. + if (comment_pos == NULL || (rs_pos != NULL + && LT_POS(*rs_pos, *comment_pos))) + { + if (is_raw != NULL && rs_pos != NULL) + *is_raw = rs_pos->lnum; + return rs_pos; + } + return comment_pos; +} + + +/* + * Return TRUE if C-indenting is on. + */ + int +cindent_on(void) +{ + return (!p_paste && (curbuf->b_p_cin +#ifdef FEAT_EVAL + || *curbuf->b_p_inde != NUL +#endif + )); +} + +// Find result cache for cpp_baseclass +typedef struct { + int found; + lpos_T lpos; +} cpp_baseclass_cache_T; + +/* + * Skip over white space and C comments within the line. + * Also skip over Perl/shell comments if desired. + */ + static char_u * +cin_skipcomment(char_u *s) +{ + while (*s) + { + char_u *prev_s = s; + + s = skipwhite(s); + + // Perl/shell # comment comment continues until eol. Require a space + // before # to avoid recognizing $#array. + if (curbuf->b_ind_hash_comment != 0 && s != prev_s && *s == '#') + { + s += STRLEN(s); + break; + } + if (*s != '/') + break; + ++s; + if (*s == '/') // slash-slash comment continues till eol + { + s += STRLEN(s); + break; + } + if (*s != '*') + break; + for (++s; *s; ++s) // skip slash-star comment + if (s[0] == '*' && s[1] == '/') + { + s += 2; + break; + } + } + return s; +} + +/* + * Return TRUE if there is no code at *s. White space and comments are + * not considered code. + */ + static int +cin_nocode(char_u *s) +{ + return *cin_skipcomment(s) == NUL; +} + +/* + * Recognize the start of a C or C++ comment. + */ + static int +cin_iscomment(char_u *p) +{ + return (p[0] == '/' && (p[1] == '*' || p[1] == '/')); +} + +/* + * Recognize the start of a "//" comment. + */ + static int +cin_islinecomment(char_u *p) +{ + return (p[0] == '/' && p[1] == '/'); +} + +/* + * Check previous lines for a "//" line comment, skipping over blank lines. + */ + static pos_T * +find_line_comment(void) // XXX +{ + static pos_T pos; + char_u *line; + char_u *p; + + pos = curwin->w_cursor; + while (--pos.lnum > 0) + { + line = ml_get(pos.lnum); + p = skipwhite(line); + if (cin_islinecomment(p)) + { + pos.col = (int)(p - line); + return &pos; + } + if (*p != NUL) + break; + } + return NULL; +} + +/* + * Return TRUE if "text" starts with "key:". + */ + static int +cin_has_js_key(char_u *text) +{ + char_u *s = skipwhite(text); + int quote = -1; + + if (*s == '\'' || *s == '"') + { + // can be 'key': or "key": + quote = *s; + ++s; + } + if (!vim_isIDc(*s)) // need at least one ID character + return FALSE; + + while (vim_isIDc(*s)) + ++s; + if (*s == quote) + ++s; + + s = cin_skipcomment(s); + + // "::" is not a label, it's C++ + return (*s == ':' && s[1] != ':'); +} + +/* + * Check if string matches "label:"; move to character after ':' if true. + * "*s" must point to the start of the label, if there is one. + */ + static int +cin_islabel_skip(char_u **s) +{ + if (!vim_isIDc(**s)) // need at least one ID character + return FALSE; + + while (vim_isIDc(**s)) + (*s)++; + + *s = cin_skipcomment(*s); + + // "::" is not a label, it's C++ + return (**s == ':' && *++*s != ':'); +} + +/* + * Recognize a scope declaration label from the 'cinscopedecls' option. + */ + static int +cin_isscopedecl(char_u *p) +{ + size_t cinsd_len; + char_u *cinsd_buf; + char_u *cinsd; + size_t len; + char_u *skip; + char_u *s = cin_skipcomment(p); + int found = FALSE; + + cinsd_len = STRLEN(curbuf->b_p_cinsd) + 1; + cinsd_buf = alloc(cinsd_len); + if (cinsd_buf == NULL) + return FALSE; + + for (cinsd = curbuf->b_p_cinsd; *cinsd; ) + { + len = copy_option_part(&cinsd, cinsd_buf, (int)cinsd_len, ","); + if (STRNCMP(s, cinsd_buf, len) == 0) + { + skip = cin_skipcomment(s + len); + if (*skip == ':' && skip[1] != ':') + { + found = TRUE; + break; + } + } + } + + vim_free(cinsd_buf); + return found; +} + +/* + * Recognize a preprocessor statement: Any line that starts with '#'. + */ + static int +cin_ispreproc(char_u *s) +{ + if (*skipwhite(s) == '#') + return TRUE; + return FALSE; +} + +/* + * Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a + * continuation line of a preprocessor statement. Decrease "*lnump" to the + * start and return the line in "*pp". + * Put the amount of indent in "*amount". + */ + static int +cin_ispreproc_cont(char_u **pp, linenr_T *lnump, int *amount) +{ + char_u *line = *pp; + linenr_T lnum = *lnump; + int retval = FALSE; + int candidate_amount = *amount; + + if (*line != NUL && line[STRLEN(line) - 1] == '\\') + candidate_amount = get_indent_lnum(lnum); + + for (;;) + { + if (cin_ispreproc(line)) + { + retval = TRUE; + *lnump = lnum; + break; + } + if (lnum == 1) + break; + line = ml_get(--lnum); + if (*line == NUL || line[STRLEN(line) - 1] != '\\') + break; + } + + if (lnum != *lnump) + *pp = ml_get(*lnump); + if (retval) + *amount = candidate_amount; + return retval; +} + + static int +cin_iselse( + char_u *p) +{ + if (*p == '}') // accept "} else" + p = cin_skipcomment(p + 1); + return (STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4])); +} + +/* + * Recognize a line that starts with '{' or '}', or ends with ';', ',', '{' or + * '}'. + * Don't consider "} else" a terminated line. + * If a line begins with an "else", only consider it terminated if no unmatched + * opening braces follow (handle "else { foo();" correctly). + * Return the character terminating the line (ending char's have precedence if + * both apply in order to determine initializations). + */ + static int +cin_isterminated( + char_u *s, + int incl_open, // include '{' at the end as terminator + int incl_comma) // recognize a trailing comma +{ + char_u found_start = 0; + unsigned n_open = 0; + int is_else = FALSE; + + s = cin_skipcomment(s); + + if (*s == '{' || (*s == '}' && !cin_iselse(s))) + found_start = *s; + + if (!found_start) + is_else = cin_iselse(s); + + while (*s) + { + // skip over comments, "" strings and 'c'haracters + s = skip_string(cin_skipcomment(s)); + if (*s == '}' && n_open > 0) + --n_open; + if ((!is_else || n_open == 0) + && (*s == ';' || *s == '}' || (incl_comma && *s == ',')) + && cin_nocode(s + 1)) + return *s; + else if (*s == '{') + { + if (incl_open && cin_nocode(s + 1)) + return *s; + else + ++n_open; + } + + if (*s) + s++; + } + return found_start; +} + +/* + * Return TRUE when "s" starts with "word" and then a non-ID character. + */ + static int +cin_starts_with(char_u *s, char *word) +{ + int l = (int)STRLEN(word); + + return (STRNCMP(s, word, l) == 0 && !vim_isIDc(s[l])); +} + +/* + * Recognize a "default" switch label. + */ + static int +cin_isdefault(char_u *s) +{ + return (STRNCMP(s, "default", 7) == 0 + && *(s = cin_skipcomment(s + 7)) == ':' + && s[1] != ':'); +} + +/* + * Recognize a switch label: "case .*:" or "default:". + */ + static int +cin_iscase( + char_u *s, + int strict) // Allow relaxed check of case statement for JS +{ + s = cin_skipcomment(s); + if (cin_starts_with(s, "case")) + { + for (s += 4; *s; ++s) + { + s = cin_skipcomment(s); + if (*s == NUL) + break; + if (*s == ':') + { + if (s[1] == ':') // skip over "::" for C++ + ++s; + else + return TRUE; + } + if (*s == '\'' && s[1] && s[2] == '\'') + s += 2; // skip over ':' + else if (*s == '/' && (s[1] == '*' || s[1] == '/')) + return FALSE; // stop at comment + else if (*s == '"') + { + // JS etc. + if (strict) + return FALSE; // stop at string + else + return TRUE; + } + } + return FALSE; + } + + if (cin_isdefault(s)) + return TRUE; + return FALSE; +} + +/* + * Recognize a label: "label:". + * Note: curwin->w_cursor must be where we are looking for the label. + */ + static int +cin_islabel(void) // XXX +{ + char_u *s; + + s = cin_skipcomment(ml_get_curline()); + + // Exclude "default" from labels, since it should be indented + // like a switch label. Same for C++ scope declarations. + if (cin_isdefault(s)) + return FALSE; + if (cin_isscopedecl(s)) + return FALSE; + + if (!cin_islabel_skip(&s)) + return FALSE; + + // Only accept a label if the previous line is terminated or is a case + // label. + pos_T cursor_save; + pos_T *trypos; + char_u *line; + + cursor_save = curwin->w_cursor; + while (curwin->w_cursor.lnum > 1) + { + --curwin->w_cursor.lnum; + + // If we're in a comment or raw string now, skip to the start of + // it. + curwin->w_cursor.col = 0; + if ((trypos = ind_find_start_CORS(NULL)) != NULL) // XXX + curwin->w_cursor = *trypos; + + line = ml_get_curline(); + if (cin_ispreproc(line)) // ignore #defines, #if, etc. + continue; + if (*(line = cin_skipcomment(line)) == NUL) + continue; + + curwin->w_cursor = cursor_save; + if (cin_isterminated(line, TRUE, FALSE) + || cin_isscopedecl(line) + || cin_iscase(line, TRUE) + || (cin_islabel_skip(&line) && cin_nocode(line))) + return TRUE; + return FALSE; + } + curwin->w_cursor = cursor_save; + return TRUE; // label at start of file??? +} + +/* + * Return TRUE if string "s" ends with the string "find", possibly followed by + * white space and comments. Skip strings and comments. + * Ignore "ignore" after "find" if it's not NULL. + */ + static int +cin_ends_in(char_u *s, char_u *find, char_u *ignore) +{ + char_u *p = s; + char_u *r; + int len = (int)STRLEN(find); + + while (*p != NUL) + { + p = cin_skipcomment(p); + if (STRNCMP(p, find, len) == 0) + { + r = skipwhite(p + len); + if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0) + r = skipwhite(r + STRLEN(ignore)); + if (cin_nocode(r)) + return TRUE; + } + if (*p != NUL) + ++p; + } + return FALSE; +} + +/* + * Recognize structure initialization and enumerations: + * "[typedef] [static|public|protected|private] enum" + * "[typedef] [static|public|protected|private] = {" + */ + static int +cin_isinit(void) +{ + char_u *s; + static char *skip[] = {"static", "public", "protected", "private"}; + + s = cin_skipcomment(ml_get_curline()); + + if (cin_starts_with(s, "typedef")) + s = cin_skipcomment(s + 7); + + for (;;) + { + int i, l; + + for (i = 0; i < (int)ARRAY_LENGTH(skip); ++i) + { + l = (int)strlen(skip[i]); + if (cin_starts_with(s, skip[i])) + { + s = cin_skipcomment(s + l); + l = 0; + break; + } + } + if (l != 0) + break; + } + + if (cin_starts_with(s, "enum")) + return TRUE; + + if (cin_ends_in(s, (char_u *)"=", (char_u *)"{")) + return TRUE; + + return FALSE; +} + +// Maximum number of lines to search back for a "namespace" line. +#define FIND_NAMESPACE_LIM 20 + +/* + * Recognize a "namespace" scope declaration. + */ + static int +cin_is_cpp_namespace(char_u *s) +{ + char_u *p; + int has_name = FALSE; + int has_name_start = FALSE; + + s = cin_skipcomment(s); + + if (STRNCMP(s, "inline", 6) == 0 && (s[6] == NUL || !vim_iswordc(s[6]))) + s = cin_skipcomment(skipwhite(s + 6)); + + if (STRNCMP(s, "namespace", 9) == 0 && (s[9] == NUL || !vim_iswordc(s[9]))) + { + p = cin_skipcomment(skipwhite(s + 9)); + while (*p != NUL) + { + if (VIM_ISWHITE(*p)) + { + has_name = TRUE; // found end of a name + p = cin_skipcomment(skipwhite(p)); + } + else if (*p == '{') + { + break; + } + else if (vim_iswordc(*p)) + { + has_name_start = TRUE; + if (has_name) + return FALSE; // word character after skipping past name + ++p; + } + else if (p[0] == ':' && p[1] == ':' && vim_iswordc(p[2])) + { + if (!has_name_start || has_name) + return FALSE; + // C++ 17 nested namespace + p += 3; + } + else + { + return FALSE; + } + } + return TRUE; + } + return FALSE; +} + +/* + * Recognize a `extern "C"` or `extern "C++"` linkage specifications. + */ + static int +cin_is_cpp_extern_c(char_u *s) +{ + char_u *p; + int has_string_literal = FALSE; + + s = cin_skipcomment(s); + if (STRNCMP(s, "extern", 6) == 0 && (s[6] == NUL || !vim_iswordc(s[6]))) + { + p = cin_skipcomment(skipwhite(s + 6)); + while (*p != NUL) + { + if (VIM_ISWHITE(*p)) + { + p = cin_skipcomment(skipwhite(p)); + } + else if (*p == '{') + { + break; + } + else if (p[0] == '"' && p[1] == 'C' && p[2] == '"') + { + if (has_string_literal) + return FALSE; + has_string_literal = TRUE; + p += 3; + } + else if (p[0] == '"' && p[1] == 'C' && p[2] == '+' && p[3] == '+' + && p[4] == '"') + { + if (has_string_literal) + return FALSE; + has_string_literal = TRUE; + p += 5; + } + else + { + return FALSE; + } + } + return has_string_literal ? TRUE : FALSE; + } + return FALSE; +} + +/* + * Return a pointer to the first non-empty non-comment character after a ':'. + * Return NULL if not found. + * case 234: a = b; + * ^ + */ + static char_u * +after_label(char_u *l) +{ + for ( ; *l; ++l) + { + if (*l == ':') + { + if (l[1] == ':') // skip over "::" for C++ + ++l; + else if (!cin_iscase(l + 1, FALSE)) + break; + } + else if (*l == '\'' && l[1] && l[2] == '\'') + l += 2; // skip over 'x' + } + if (*l == NUL) + return NULL; + l = cin_skipcomment(l + 1); + if (*l == NUL) + return NULL; + return l; +} + +/* + * Get indent of line "lnum", skipping a label. + * Return 0 if there is nothing after the label. + */ + static int +get_indent_nolabel (linenr_T lnum) // XXX +{ + char_u *l; + pos_T fp; + colnr_T col; + char_u *p; + + l = ml_get(lnum); + p = after_label(l); + if (p == NULL) + return 0; + + fp.col = (colnr_T)(p - l); + fp.lnum = lnum; + getvcol(curwin, &fp, &col, NULL, NULL); + return (int)col; +} + +/* + * Find indent for line "lnum", ignoring any case or jump label. + * Also return a pointer to the text (after the label) in "pp". + * label: if (asdf && asdfasdf) + * ^ + */ + static int +skip_label(linenr_T lnum, char_u **pp) +{ + char_u *l; + int amount; + pos_T cursor_save; + + cursor_save = curwin->w_cursor; + curwin->w_cursor.lnum = lnum; + l = ml_get_curline(); + // XXX + if (cin_iscase(l, FALSE) || cin_isscopedecl(l) || cin_islabel()) + { + amount = get_indent_nolabel(lnum); + l = after_label(ml_get_curline()); + if (l == NULL) // just in case + l = ml_get_curline(); + } + else + { + amount = get_indent(); + l = ml_get_curline(); + } + *pp = l; + + curwin->w_cursor = cursor_save; + return amount; +} + +/* + * Return the indent of the first variable name after a type in a declaration. + * int a, indent of "a" + * static struct foo b, indent of "b" + * enum bla c, indent of "c" + * Returns zero when it doesn't look like a declaration. + */ + static int +cin_first_id_amount(void) +{ + char_u *line, *p, *s; + int len; + pos_T fp; + colnr_T col; + + line = ml_get_curline(); + p = skipwhite(line); + len = (int)(skiptowhite(p) - p); + if (len == 6 && STRNCMP(p, "static", 6) == 0) + { + p = skipwhite(p + 6); + len = (int)(skiptowhite(p) - p); + } + if (len == 6 && STRNCMP(p, "struct", 6) == 0) + p = skipwhite(p + 6); + else if (len == 4 && STRNCMP(p, "enum", 4) == 0) + p = skipwhite(p + 4); + else if ((len == 8 && STRNCMP(p, "unsigned", 8) == 0) + || (len == 6 && STRNCMP(p, "signed", 6) == 0)) + { + s = skipwhite(p + len); + if ((STRNCMP(s, "int", 3) == 0 && VIM_ISWHITE(s[3])) + || (STRNCMP(s, "long", 4) == 0 && VIM_ISWHITE(s[4])) + || (STRNCMP(s, "short", 5) == 0 && VIM_ISWHITE(s[5])) + || (STRNCMP(s, "char", 4) == 0 && VIM_ISWHITE(s[4]))) + p = s; + } + for (len = 0; vim_isIDc(p[len]); ++len) + ; + if (len == 0 || !VIM_ISWHITE(p[len]) || cin_nocode(p)) + return 0; + + p = skipwhite(p + len); + fp.lnum = curwin->w_cursor.lnum; + fp.col = (colnr_T)(p - line); + getvcol(curwin, &fp, &col, NULL, NULL); + return (int)col; +} + +/* + * Return the indent of the first non-blank after an equal sign. + * char *foo = "here"; + * Return zero if no (useful) equal sign found. + * Return -1 if the line above "lnum" ends in a backslash. + * foo = "asdf\ + * asdf\ + * here"; + */ + static int +cin_get_equal_amount(linenr_T lnum) +{ + char_u *line; + char_u *s; + colnr_T col; + pos_T fp; + + if (lnum > 1) + { + line = ml_get(lnum - 1); + if (*line != NUL && line[STRLEN(line) - 1] == '\\') + return -1; + } + + line = s = ml_get(lnum); + while (*s != NUL && vim_strchr((char_u *)"=;{}\"'", *s) == NULL) + { + if (cin_iscomment(s)) // ignore comments + s = cin_skipcomment(s); + else + ++s; + } + if (*s != '=') + return 0; + + s = skipwhite(s + 1); + if (cin_nocode(s)) + return 0; + + if (*s == '"') // nice alignment for continued strings + ++s; + + fp.lnum = lnum; + fp.col = (colnr_T)(s - line); + getvcol(curwin, &fp, &col, NULL, NULL); + return (int)col; +} + +/* + * Skip strings, chars and comments until at or past "trypos". + * Return the column found. + */ + static int +cin_skip2pos(pos_T *trypos) +{ + char_u *line; + char_u *p; + char_u *new_p; + + p = line = ml_get(trypos->lnum); + while (*p && (colnr_T)(p - line) < trypos->col) + { + if (cin_iscomment(p)) + p = cin_skipcomment(p); + else + { + new_p = skip_string(p); + if (new_p == p) + ++p; + else + p = new_p; + } + } + return (int)(p - line); +} + + static pos_T * +find_match_char(int c, int ind_maxparen) // XXX +{ + pos_T cursor_save; + pos_T *trypos; + static pos_T pos_copy; + int ind_maxp_wk; + + cursor_save = curwin->w_cursor; + ind_maxp_wk = ind_maxparen; +retry: + if ((trypos = findmatchlimit(NULL, c, 0, ind_maxp_wk)) != NULL) + { + // check if the ( is in a // comment + if ((colnr_T)cin_skip2pos(trypos) > trypos->col) + { + ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum - trypos->lnum); + if (ind_maxp_wk > 0) + { + curwin->w_cursor = *trypos; + curwin->w_cursor.col = 0; // XXX + goto retry; + } + trypos = NULL; + } + else + { + pos_T *trypos_wk; + + pos_copy = *trypos; // copy trypos, findmatch will change it + trypos = &pos_copy; + curwin->w_cursor = *trypos; + if ((trypos_wk = ind_find_start_CORS(NULL)) != NULL) // XXX + { + ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum + - trypos_wk->lnum); + if (ind_maxp_wk > 0) + { + curwin->w_cursor = *trypos_wk; + goto retry; + } + trypos = NULL; + } + } + } + curwin->w_cursor = cursor_save; + return trypos; +} + +/* + * Find the matching '(', ignoring it if it is in a comment. + * Return NULL if no match found. + */ + static pos_T * +find_match_paren(int ind_maxparen) // XXX +{ + return find_match_char('(', ind_maxparen); +} + +/* + * Set w_cursor.col to the column number of the last unmatched ')' or '{' in + * line "l". "l" must point to the start of the line. + */ + static int +find_last_paren(char_u *l, int start, int end) +{ + int i; + int retval = FALSE; + int open_count = 0; + + curwin->w_cursor.col = 0; // default is start of line + + for (i = 0; l[i] != NUL; i++) + { + i = (int)(cin_skipcomment(l + i) - l); // ignore parens in comments + i = (int)(skip_string(l + i) - l); // ignore parens in quotes + if (l[i] == start) + ++open_count; + else if (l[i] == end) + { + if (open_count > 0) + --open_count; + else + { + curwin->w_cursor.col = i; + retval = TRUE; + } + } + } + return retval; +} + +/* + * Recognize the basic picture of a function declaration -- it needs to + * have an open paren somewhere and a close paren at the end of the line and + * no semicolons anywhere. + * When a line ends in a comma we continue looking in the next line. + * "sp" points to a string with the line. When looking at other lines it must + * be restored to the line. When it's NULL fetch lines here. + * "first_lnum" is where we start looking. + * "min_lnum" is the line before which we will not be looking. + */ + static int +cin_isfuncdecl( + char_u **sp, + linenr_T first_lnum, + linenr_T min_lnum) +{ + char_u *s; + linenr_T lnum = first_lnum; + linenr_T save_lnum = curwin->w_cursor.lnum; + int retval = FALSE; + pos_T *trypos; + int just_started = TRUE; + + if (sp == NULL) + s = ml_get(lnum); + else + s = *sp; + + curwin->w_cursor.lnum = lnum; + if (find_last_paren(s, '(', ')') + && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) + { + lnum = trypos->lnum; + if (lnum < min_lnum) + { + curwin->w_cursor.lnum = save_lnum; + return FALSE; + } + + s = ml_get(lnum); + } + curwin->w_cursor.lnum = save_lnum; + + // Ignore line starting with #. + if (cin_ispreproc(s)) + return FALSE; + + while (*s && *s != '(' && *s != ';' && *s != '\'' && *s != '"') + { + if (cin_iscomment(s)) // ignore comments + s = cin_skipcomment(s); + else if (*s == ':') + { + if (*(s + 1) == ':') + s += 2; + else + // To avoid a mistake in the following situation: + // A::A(int a, int b) + // : a(0) // <--not a function decl + // , b(0) + // {... + return FALSE; + } + else + ++s; + } + if (*s != '(') + return FALSE; // ';', ' or " before any () or no '(' + + while (*s && *s != ';' && *s != '\'' && *s != '"') + { + if (*s == ')' && cin_nocode(s + 1)) + { + // ')' at the end: may have found a match + // Check for the previous line not to end in a backslash: + // #if defined(x) && {backslash} + // defined(y) + lnum = first_lnum - 1; + s = ml_get(lnum); + if (*s == NUL || s[STRLEN(s) - 1] != '\\') + retval = TRUE; + goto done; + } + if ((*s == ',' && cin_nocode(s + 1)) || s[1] == NUL || cin_nocode(s)) + { + int comma = (*s == ','); + + // ',' at the end: continue looking in the next line. + // At the end: check for ',' in the next line, for this style: + // func(arg1 + // , arg2) + for (;;) + { + if (lnum >= curbuf->b_ml.ml_line_count) + break; + s = ml_get(++lnum); + if (!cin_ispreproc(s)) + break; + } + if (lnum >= curbuf->b_ml.ml_line_count) + break; + // Require a comma at end of the line or a comma or ')' at the + // start of next line. + s = skipwhite(s); + if (!just_started && (!comma && *s != ',' && *s != ')')) + break; + just_started = FALSE; + } + else if (cin_iscomment(s)) // ignore comments + s = cin_skipcomment(s); + else + { + ++s; + just_started = FALSE; + } + } + +done: + if (lnum != first_lnum && sp != NULL) + *sp = ml_get(first_lnum); + + return retval; +} + + static int +cin_isif(char_u *p) +{ + return (STRNCMP(p, "if", 2) == 0 && !vim_isIDc(p[2])); +} + + static int +cin_isdo(char_u *p) +{ + return (STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2])); +} + +/* + * Check if this is a "while" that should have a matching "do". + * We only accept a "while (condition) ;", with only white space between the + * ')' and ';'. The condition may be spread over several lines. + */ + static int +cin_iswhileofdo (char_u *p, linenr_T lnum) // XXX +{ + pos_T cursor_save; + pos_T *trypos; + int retval = FALSE; + + p = cin_skipcomment(p); + if (*p == '}') // accept "} while (cond);" + p = cin_skipcomment(p + 1); + if (cin_starts_with(p, "while")) + { + cursor_save = curwin->w_cursor; + curwin->w_cursor.lnum = lnum; + curwin->w_cursor.col = 0; + p = ml_get_curline(); + while (*p && *p != 'w') // skip any '}', until the 'w' of the "while" + { + ++p; + ++curwin->w_cursor.col; + } + if ((trypos = findmatchlimit(NULL, 0, 0, + curbuf->b_ind_maxparen)) != NULL + && *cin_skipcomment(ml_get_pos(trypos) + 1) == ';') + retval = TRUE; + curwin->w_cursor = cursor_save; + } + return retval; +} + +/* + * Check whether in "p" there is an "if", "for" or "while" before "*poffset". + * Return 0 if there is none. + * Otherwise return !0 and update "*poffset" to point to the place where the + * string was found. + */ + static int +cin_is_if_for_while_before_offset(char_u *line, int *poffset) +{ + int offset = *poffset; + + if (offset-- < 2) + return 0; + while (offset > 2 && VIM_ISWHITE(line[offset])) + --offset; + + offset -= 1; + if (!STRNCMP(line + offset, "if", 2)) + goto probablyFound; + + if (offset >= 1) + { + offset -= 1; + if (!STRNCMP(line + offset, "for", 3)) + goto probablyFound; + + if (offset >= 2) + { + offset -= 2; + if (!STRNCMP(line + offset, "while", 5)) + goto probablyFound; + } + } + return 0; + +probablyFound: + if (!offset || !vim_isIDc(line[offset - 1])) + { + *poffset = offset; + return 1; + } + return 0; +} + +/* + * Return TRUE if we are at the end of a do-while. + * do + * nothing; + * while (foo + * && bar); <-- here + * Adjust the cursor to the line with "while". + */ + static int +cin_iswhileofdo_end(int terminated) +{ + char_u *line; + char_u *p; + char_u *s; + pos_T *trypos; + int i; + + if (terminated != ';') // there must be a ';' at the end + return FALSE; + + p = line = ml_get_curline(); + while (*p != NUL) + { + p = cin_skipcomment(p); + if (*p == ')') + { + s = skipwhite(p + 1); + if (*s == ';' && cin_nocode(s + 1)) + { + // Found ");" at end of the line, now check there is "while" + // before the matching '('. XXX + i = (int)(p - line); + curwin->w_cursor.col = i; + trypos = find_match_paren(curbuf->b_ind_maxparen); + if (trypos != NULL) + { + s = cin_skipcomment(ml_get(trypos->lnum)); + if (*s == '}') // accept "} while (cond);" + s = cin_skipcomment(s + 1); + if (cin_starts_with(s, "while")) + { + curwin->w_cursor.lnum = trypos->lnum; + return TRUE; + } + } + + // Searching may have made "line" invalid, get it again. + line = ml_get_curline(); + p = line + i; + } + } + if (*p != NUL) + ++p; + } + return FALSE; +} + + static int +cin_isbreak(char_u *p) +{ + return (STRNCMP(p, "break", 5) == 0 && !vim_isIDc(p[5])); +} + +/* + * Find the position of a C++ base-class declaration or + * constructor-initialization. eg: + * + * class MyClass : + * baseClass <-- here + * class MyClass : public baseClass, + * anotherBaseClass <-- here (should probably lineup ??) + * MyClass::MyClass(...) : + * baseClass(...) <-- here (constructor-initialization) + * + * This is a lot of guessing. Watch out for "cond ? func() : foo". + */ + static int +cin_is_cpp_baseclass( + cpp_baseclass_cache_T *cached) // input and output +{ + lpos_T *pos = &cached->lpos; // find position + char_u *s; + int class_or_struct, lookfor_ctor_init, cpp_base_class; + linenr_T lnum = curwin->w_cursor.lnum; + char_u *line = ml_get_curline(); + + if (pos->lnum <= lnum) + return cached->found; // Use the cached result + + pos->col = 0; + + s = skipwhite(line); + if (*s == '#') // skip #define FOO x ? (x) : x + return FALSE; + s = cin_skipcomment(s); + if (*s == NUL) + return FALSE; + + cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE; + + // Search for a line starting with '#', empty, ending in ';' or containing + // '{' or '}' and start below it. This handles the following situations: + // a = cond ? + // func() : + // asdf; + // func::foo() + // : something + // {} + // Foo::Foo (int one, int two) + // : something(4), + // somethingelse(3) + // {} + while (lnum > 1) + { + line = ml_get(lnum - 1); + s = skipwhite(line); + if (*s == '#' || *s == NUL) + break; + while (*s != NUL) + { + s = cin_skipcomment(s); + if (*s == '{' || *s == '}' + || (*s == ';' && cin_nocode(s + 1))) + break; + if (*s != NUL) + ++s; + } + if (*s != NUL) + break; + --lnum; + } + + pos->lnum = lnum; + line = ml_get(lnum); + s = line; + for (;;) + { + if (*s == NUL) + { + if (lnum == curwin->w_cursor.lnum) + break; + // Continue in the cursor line. + line = ml_get(++lnum); + s = line; + } + if (s == line) + { + // don't recognize "case (foo):" as a baseclass + if (cin_iscase(s, FALSE)) + break; + s = cin_skipcomment(line); + if (*s == NUL) + continue; + } + + if (s[0] == '"' || (s[0] == 'R' && s[1] == '"')) + s = skip_string(s) + 1; + else if (s[0] == ':') + { + if (s[1] == ':') + { + // skip double colon. It can't be a constructor + // initialization any more + lookfor_ctor_init = FALSE; + s = cin_skipcomment(s + 2); + } + else if (lookfor_ctor_init || class_or_struct) + { + // we have something found, that looks like the start of + // cpp-base-class-declaration or constructor-initialization + cpp_base_class = TRUE; + lookfor_ctor_init = class_or_struct = FALSE; + pos->col = 0; + s = cin_skipcomment(s + 1); + } + else + s = cin_skipcomment(s + 1); + } + else if ((STRNCMP(s, "class", 5) == 0 && !vim_isIDc(s[5])) + || (STRNCMP(s, "struct", 6) == 0 && !vim_isIDc(s[6]))) + { + class_or_struct = TRUE; + lookfor_ctor_init = FALSE; + + if (*s == 'c') + s = cin_skipcomment(s + 5); + else + s = cin_skipcomment(s + 6); + } + else + { + if (s[0] == '{' || s[0] == '}' || s[0] == ';') + { + cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE; + } + else if (s[0] == ')') + { + // Constructor-initialization is assumed if we come across + // something like "):" + class_or_struct = FALSE; + lookfor_ctor_init = TRUE; + } + else if (s[0] == '?') + { + // Avoid seeing '() :' after '?' as constructor init. + return FALSE; + } + else if (!vim_isIDc(s[0])) + { + // if it is not an identifier, we are wrong + class_or_struct = FALSE; + lookfor_ctor_init = FALSE; + } + else if (pos->col == 0) + { + // it can't be a constructor-initialization any more + lookfor_ctor_init = FALSE; + + // the first statement starts here: lineup with this one... + if (cpp_base_class) + pos->col = (colnr_T)(s - line); + } + + // When the line ends in a comma don't align with it. + if (lnum == curwin->w_cursor.lnum && *s == ',' && cin_nocode(s + 1)) + pos->col = 0; + + s = cin_skipcomment(s + 1); + } + } + + cached->found = cpp_base_class; + if (cpp_base_class) + pos->lnum = lnum; + return cpp_base_class; +} + + static int +get_baseclass_amount(int col) +{ + int amount; + colnr_T vcol; + pos_T *trypos; + + if (col == 0) + { + amount = get_indent(); + if (find_last_paren(ml_get_curline(), '(', ')') + && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) + amount = get_indent_lnum(trypos->lnum); // XXX + if (!cin_ends_in(ml_get_curline(), (char_u *)",", NULL)) + amount += curbuf->b_ind_cpp_baseclass; + } + else + { + curwin->w_cursor.col = col; + getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); + amount = (int)vcol; + } + if (amount < curbuf->b_ind_cpp_baseclass) + amount = curbuf->b_ind_cpp_baseclass; + return amount; +} + +/* + * Find the '{' at the start of the block we are in. + * Return NULL if no match found. + * Ignore a '{' that is in a comment, makes indenting the next three lines + * work. + */ +// foo() +// { +// } + + static pos_T * +find_start_brace(void) // XXX +{ + pos_T cursor_save; + pos_T *trypos; + pos_T *pos; + static pos_T pos_copy; + + cursor_save = curwin->w_cursor; + while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL) + { + pos_copy = *trypos; // copy pos_T, next findmatch will change it + trypos = &pos_copy; + curwin->w_cursor = *trypos; + pos = NULL; + // ignore the { if it's in a // or / * * / comment + if ((colnr_T)cin_skip2pos(trypos) == trypos->col + && (pos = ind_find_start_CORS(NULL)) == NULL) // XXX + break; + if (pos != NULL) + curwin->w_cursor = *pos; + } + curwin->w_cursor = cursor_save; + return trypos; +} + +/* + * Find the matching '(', ignoring it if it is in a comment or before an + * unmatched {. + * Return NULL if no match found. + */ + static pos_T * +find_match_paren_after_brace (int ind_maxparen) // XXX +{ + pos_T *trypos = find_match_paren(ind_maxparen); + + if (trypos == NULL) + return NULL; + + pos_T *tryposBrace = find_start_brace(); + + // If both an unmatched '(' and '{' is found. Ignore the '(' + // position if the '{' is further down. + if (tryposBrace != NULL + && (trypos->lnum != tryposBrace->lnum + ? trypos->lnum < tryposBrace->lnum + : trypos->col < tryposBrace->col)) + trypos = NULL; + return trypos; +} + +/* + * Return ind_maxparen corrected for the difference in line number between the + * cursor position and "startpos". This makes sure that searching for a + * matching paren above the cursor line doesn't find a match because of + * looking a few lines further. + */ + static int +corr_ind_maxparen(pos_T *startpos) +{ + long n = (long)startpos->lnum - (long)curwin->w_cursor.lnum; + + if (n > 0 && n < curbuf->b_ind_maxparen / 2) + return curbuf->b_ind_maxparen - (int)n; + return curbuf->b_ind_maxparen; +} + +/* + * Parse 'cinoptions' and set the values in "curbuf". + * Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes. + */ + void +parse_cino(buf_T *buf) +{ + char_u *p; + char_u *l; + char_u *digits; + int n; + int divider; + int fraction = 0; + int sw = (int)get_sw_value(buf); + + // Set the default values. + + // Spaces from a block's opening brace the prevailing indent for that + // block should be. + buf->b_ind_level = sw; + + // Spaces from the edge of the line an open brace that's at the end of a + // line is imagined to be. + buf->b_ind_open_imag = 0; + + // Spaces from the prevailing indent for a line that is not preceded by + // an opening brace. + buf->b_ind_no_brace = 0; + + // Column where the first { of a function should be located }. + buf->b_ind_first_open = 0; + + // Spaces from the prevailing indent a leftmost open brace should be + // located. + buf->b_ind_open_extra = 0; + + // Spaces from the matching open brace (real location for one at the left + // edge; imaginary location from one that ends a line) the matching close + // brace should be located. + buf->b_ind_close_extra = 0; + + // Spaces from the edge of the line an open brace sitting in the leftmost + // column is imagined to be. + buf->b_ind_open_left_imag = 0; + + // Spaces jump labels should be shifted to the left if N is non-negative, + // otherwise the jump label will be put to column 1. + buf->b_ind_jump_label = -1; + + // Spaces from the switch() indent a "case xx" label should be located. + buf->b_ind_case = sw; + + // Spaces from the "case xx:" code after a switch() should be located. + buf->b_ind_case_code = sw; + + // Lineup break at end of case in switch() with case label. + buf->b_ind_case_break = 0; + + // Spaces from the class declaration indent a scope declaration label + // should be located. + buf->b_ind_scopedecl = sw; + + // Spaces from the scope declaration label code should be located. + buf->b_ind_scopedecl_code = sw; + + // Amount K&R-style parameters should be indented. + buf->b_ind_param = sw; + + // Amount a function type spec should be indented. + buf->b_ind_func_type = sw; + + // Amount a cpp base class declaration or constructor initialization + // should be indented. + buf->b_ind_cpp_baseclass = sw; + + // additional spaces beyond the prevailing indent a continuation line + // should be located. + buf->b_ind_continuation = sw; + + // Spaces from the indent of the line with an unclosed parenthesis. + buf->b_ind_unclosed = sw * 2; + + // Spaces from the indent of the line with an unclosed parenthesis, which + // itself is also unclosed. + buf->b_ind_unclosed2 = sw; + + // Suppress ignoring spaces from the indent of a line starting with an + // unclosed parenthesis. + buf->b_ind_unclosed_noignore = 0; + + // If the opening paren is the last nonwhite character on the line, and + // b_ind_unclosed_wrapped is nonzero, use this indent relative to the outer + // context (for very long lines). + buf->b_ind_unclosed_wrapped = 0; + + // Suppress ignoring white space when lining up with the character after + // an unclosed parenthesis. + buf->b_ind_unclosed_whiteok = 0; + + // Indent a closing parenthesis under the line start of the matching + // opening parenthesis. + buf->b_ind_matching_paren = 0; + + // Indent a closing parenthesis under the previous line. + buf->b_ind_paren_prev = 0; + + // Extra indent for comments. + buf->b_ind_comment = 0; + + // Spaces from the comment opener when there is nothing after it. + buf->b_ind_in_comment = 3; + + // Boolean: if non-zero, use b_ind_in_comment even if there is something + // after the comment opener. + buf->b_ind_in_comment2 = 0; + + // Max lines to search for an open paren. + buf->b_ind_maxparen = 20; + + // Max lines to search for an open comment. + buf->b_ind_maxcomment = 70; + + // Handle braces for java code. + buf->b_ind_java = 0; + + // Not to confuse JS object properties with labels. + buf->b_ind_js = 0; + + // Handle blocked cases correctly. + buf->b_ind_keep_case_label = 0; + + // Handle C++ namespace. + buf->b_ind_cpp_namespace = 0; + + // Handle continuation lines containing conditions of if(), for() and + // while(). + buf->b_ind_if_for_while = 0; + + // indentation for # comments + buf->b_ind_hash_comment = 0; + + // Handle C++ extern "C" or "C++" + buf->b_ind_cpp_extern_c = 0; + + // Handle C #pragma directives + buf->b_ind_pragma = 0; + + for (p = buf->b_p_cino; *p; ) + { + l = p++; + if (*p == '-') + ++p; + digits = p; // remember where the digits start + n = getdigits(&p); + divider = 0; + if (*p == '.') // ".5s" means a fraction + { + fraction = atol((char *)++p); + while (VIM_ISDIGIT(*p)) + { + ++p; + if (divider) + divider *= 10; + else + divider = 10; + } + } + if (*p == 's') // "2s" means two times 'shiftwidth' + { + if (p == digits) + n = sw; // just "s" is one 'shiftwidth' + else + { + n *= sw; + if (divider) + n += (sw * fraction + divider / 2) / divider; + } + ++p; + } + if (l[1] == '-') + n = -n; + + // When adding an entry here, also update the default 'cinoptions' in + // doc/indent.txt, and add explanation for it! + switch (*l) + { + case '>': buf->b_ind_level = n; break; + case 'e': buf->b_ind_open_imag = n; break; + case 'n': buf->b_ind_no_brace = n; break; + case 'f': buf->b_ind_first_open = n; break; + case '{': buf->b_ind_open_extra = n; break; + case '}': buf->b_ind_close_extra = n; break; + case '^': buf->b_ind_open_left_imag = n; break; + case 'L': buf->b_ind_jump_label = n; break; + case ':': buf->b_ind_case = n; break; + case '=': buf->b_ind_case_code = n; break; + case 'b': buf->b_ind_case_break = n; break; + case 'p': buf->b_ind_param = n; break; + case 't': buf->b_ind_func_type = n; break; + case '/': buf->b_ind_comment = n; break; + case 'c': buf->b_ind_in_comment = n; break; + case 'C': buf->b_ind_in_comment2 = n; break; + case 'i': buf->b_ind_cpp_baseclass = n; break; + case '+': buf->b_ind_continuation = n; break; + case '(': buf->b_ind_unclosed = n; break; + case 'u': buf->b_ind_unclosed2 = n; break; + case 'U': buf->b_ind_unclosed_noignore = n; break; + case 'W': buf->b_ind_unclosed_wrapped = n; break; + case 'w': buf->b_ind_unclosed_whiteok = n; break; + case 'm': buf->b_ind_matching_paren = n; break; + case 'M': buf->b_ind_paren_prev = n; break; + case ')': buf->b_ind_maxparen = n; break; + case '*': buf->b_ind_maxcomment = n; break; + case 'g': buf->b_ind_scopedecl = n; break; + case 'h': buf->b_ind_scopedecl_code = n; break; + case 'j': buf->b_ind_java = n; break; + case 'J': buf->b_ind_js = n; break; + case 'l': buf->b_ind_keep_case_label = n; break; + case '#': buf->b_ind_hash_comment = n; break; + case 'N': buf->b_ind_cpp_namespace = n; break; + case 'k': buf->b_ind_if_for_while = n; break; + case 'E': buf->b_ind_cpp_extern_c = n; break; + case 'P': buf->b_ind_pragma = n; break; + } + if (*p == ',') + ++p; + } +} + + static int +find_match(int lookfor, linenr_T ourscope) +{ + char_u *look; + pos_T *theirscope; + char_u *mightbeif; + int elselevel; + int whilelevel; + + if (lookfor == LOOKFOR_IF) + { + elselevel = 1; + whilelevel = 0; + } + else + { + elselevel = 0; + whilelevel = 1; + } + + curwin->w_cursor.col = 0; + + while (curwin->w_cursor.lnum > ourscope + 1) + { + curwin->w_cursor.lnum--; + curwin->w_cursor.col = 0; + + look = cin_skipcomment(ml_get_curline()); + if (cin_iselse(look) + || cin_isif(look) + || cin_isdo(look) // XXX + || cin_iswhileofdo(look, curwin->w_cursor.lnum)) + { + // if we've gone outside the braces entirely, + // we must be out of scope... + theirscope = find_start_brace(); // XXX + if (theirscope == NULL) + break; + + // and if the brace enclosing this is further + // back than the one enclosing the else, we're + // out of luck too. + if (theirscope->lnum < ourscope) + break; + + // and if they're enclosed in a *deeper* brace, + // then we can ignore it because it's in a + // different scope... + if (theirscope->lnum > ourscope) + continue; + + // if it was an "else" (that's not an "else if") + // then we need to go back to another if, so + // increment elselevel + look = cin_skipcomment(ml_get_curline()); + if (cin_iselse(look)) + { + mightbeif = cin_skipcomment(look + 4); + if (!cin_isif(mightbeif)) + ++elselevel; + continue; + } + + // if it was a "while" then we need to go back to + // another "do", so increment whilelevel. XXX + if (cin_iswhileofdo(look, curwin->w_cursor.lnum)) + { + ++whilelevel; + continue; + } + + // If it's an "if" decrement elselevel + look = cin_skipcomment(ml_get_curline()); + if (cin_isif(look)) + { + elselevel--; + // When looking for an "if" ignore "while"s that + // get in the way. + if (elselevel == 0 && lookfor == LOOKFOR_IF) + whilelevel = 0; + } + + // If it's a "do" decrement whilelevel + if (cin_isdo(look)) + whilelevel--; + + // if we've used up all the elses, then + // this must be the if that we want! + // match the indent level of that if. + if (elselevel <= 0 && whilelevel <= 0) + return OK; + } + } + return FAIL; +} + +/* + * Return the desired indent for C code. + * Return -1 if the indent should be left alone (inside a raw string). + */ + int +get_c_indent(void) +{ + pos_T cur_curpos; + int amount; + int scope_amount; + int cur_amount = MAXCOL; + colnr_T col; + char_u *theline; + char_u *linecopy; + pos_T *trypos; + pos_T *comment_pos; + pos_T *tryposBrace = NULL; + pos_T tryposCopy; + pos_T our_paren_pos; + char_u *start; + int start_brace; +#define BRACE_IN_COL0 1 // '{' is in column 0 +#define BRACE_AT_START 2 // '{' is at start of line +#define BRACE_AT_END 3 // '{' is at end of line + linenr_T ourscope; + char_u *l; + char_u *look; + char_u terminated; + int lookfor; + int whilelevel; + linenr_T lnum; + int n; + int iscase; + int lookfor_break; + int lookfor_cpp_namespace = FALSE; + int cont_amount = 0; // amount for continuation line + int original_line_islabel; + int added_to_amount = 0; + int js_cur_has_key = 0; + linenr_T raw_string_start = 0; + cpp_baseclass_cache_T cache_cpp_baseclass = { FALSE, { MAXLNUM, 0 } }; + + // make a copy, value is changed below + int ind_continuation = curbuf->b_ind_continuation; + + // remember where the cursor was when we started + cur_curpos = curwin->w_cursor; + + // if we are at line 1 zero indent is fine, right? + if (cur_curpos.lnum == 1) + return 0; + + // Get a copy of the current contents of the line. + // This is required, because only the most recent line obtained with + // ml_get is valid! + linecopy = vim_strsave(ml_get(cur_curpos.lnum)); + if (linecopy == NULL) + return 0; + + // In insert mode and the cursor is on a ')' truncate the line at the + // cursor position. We don't want to line up with the matching '(' when + // inserting new stuff. + // For unknown reasons the cursor might be past the end of the line, thus + // check for that. + if ((State & MODE_INSERT) + && curwin->w_cursor.col < (colnr_T)STRLEN(linecopy) + && linecopy[curwin->w_cursor.col] == ')') + linecopy[curwin->w_cursor.col] = NUL; + + theline = skipwhite(linecopy); + + // move the cursor to the start of the line + + curwin->w_cursor.col = 0; + + original_line_islabel = cin_islabel(); // XXX + + // If we are inside a raw string don't change the indent. + // Ignore a raw string inside a comment. + comment_pos = ind_find_start_comment(); + if (comment_pos != NULL) + { + // findmatchlimit() static pos is overwritten, make a copy + tryposCopy = *comment_pos; + comment_pos = &tryposCopy; + } + trypos = find_start_rawstring(curbuf->b_ind_maxcomment); + if (trypos != NULL && (comment_pos == NULL + || LT_POS(*trypos, *comment_pos))) + { + amount = -1; + goto laterend; + } + + // #defines and so on go at the left when included in 'cinkeys', + // excluding pragmas when customized in 'cinoptions' + if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE))) + { + char_u *directive = skipwhite(theline + 1); + if (curbuf->b_ind_pragma == 0 || STRNCMP(directive, "pragma", 6) != 0) + { + amount = curbuf->b_ind_hash_comment; + goto theend; + } + } + + // Is it a non-case label? Then that goes at the left margin too unless: + // - JS flag is set. + // - 'L' item has a positive value. + if (original_line_islabel && !curbuf->b_ind_js + && curbuf->b_ind_jump_label < 0) + { + amount = 0; + goto theend; + } + + // If we're inside a "//" comment and there is a "//" comment in a + // previous line, lineup with that one. + if (cin_islinecomment(theline)) + { + pos_T linecomment_pos; + + trypos = find_line_comment(); // XXX + if (trypos == NULL && curwin->w_cursor.lnum > 1) + { + // There may be a statement before the comment, search from the end + // of the line for a comment start. + linecomment_pos.col = + check_linecomment(ml_get(curwin->w_cursor.lnum - 1)); + if (linecomment_pos.col != MAXCOL) + { + trypos = &linecomment_pos; + trypos->lnum = curwin->w_cursor.lnum - 1; + } + } + if (trypos != NULL) + { + // find how indented the line beginning the comment is + getvcol(curwin, trypos, &col, NULL, NULL); + amount = col; + goto theend; + } + } + + // If we're inside a comment and not looking at the start of the + // comment, try using the 'comments' option. + if (!cin_iscomment(theline) && comment_pos != NULL) // XXX + { + int lead_start_len = 2; + int lead_middle_len = 1; + char_u lead_start[COM_MAX_LEN]; // start-comment string + char_u lead_middle[COM_MAX_LEN]; // middle-comment string + char_u lead_end[COM_MAX_LEN]; // end-comment string + char_u *p; + int start_align = 0; + int start_off = 0; + int done = FALSE; + + // find how indented the line beginning the comment is + getvcol(curwin, comment_pos, &col, NULL, NULL); + amount = col; + *lead_start = NUL; + *lead_middle = NUL; + + p = curbuf->b_p_com; + while (*p != NUL) + { + int align = 0; + int off = 0; + int what = 0; + + while (*p != NUL && *p != ':') + { + if (*p == COM_START || *p == COM_END || *p == COM_MIDDLE) + what = *p++; + else if (*p == COM_LEFT || *p == COM_RIGHT) + align = *p++; + else if (VIM_ISDIGIT(*p) || *p == '-') + off = getdigits(&p); + else + ++p; + } + + if (*p == ':') + ++p; + (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ","); + if (what == COM_START) + { + STRCPY(lead_start, lead_end); + lead_start_len = (int)STRLEN(lead_start); + start_off = off; + start_align = align; + } + else if (what == COM_MIDDLE) + { + STRCPY(lead_middle, lead_end); + lead_middle_len = (int)STRLEN(lead_middle); + } + else if (what == COM_END) + { + // If our line starts with the middle comment string, line it + // up with the comment opener per the 'comments' option. + if (STRNCMP(theline, lead_middle, lead_middle_len) == 0 + && STRNCMP(theline, lead_end, STRLEN(lead_end)) != 0) + { + done = TRUE; + if (curwin->w_cursor.lnum > 1) + { + // If the start comment string matches in the previous + // line, use the indent of that line plus offset. If + // the middle comment string matches in the previous + // line, use the indent of that line. XXX + look = skipwhite(ml_get(curwin->w_cursor.lnum - 1)); + if (STRNCMP(look, lead_start, lead_start_len) == 0) + amount = get_indent_lnum(curwin->w_cursor.lnum - 1); + else if (STRNCMP(look, lead_middle, + lead_middle_len) == 0) + { + amount = get_indent_lnum(curwin->w_cursor.lnum - 1); + break; + } + // If the start comment string doesn't match with the + // start of the comment, skip this entry. XXX + else if (STRNCMP(ml_get(comment_pos->lnum) + + comment_pos->col, + lead_start, lead_start_len) != 0) + continue; + } + if (start_off != 0) + amount += start_off; + else if (start_align == COM_RIGHT) + amount += vim_strsize(lead_start) + - vim_strsize(lead_middle); + break; + } + + // If our line starts with the end comment string, line it up + // with the middle comment + if (STRNCMP(theline, lead_middle, lead_middle_len) != 0 + && STRNCMP(theline, lead_end, STRLEN(lead_end)) == 0) + { + amount = get_indent_lnum(curwin->w_cursor.lnum - 1); + // XXX + if (off != 0) + amount += off; + else if (align == COM_RIGHT) + amount += vim_strsize(lead_start) + - vim_strsize(lead_middle); + done = TRUE; + break; + } + } + } + + // If our line starts with an asterisk, line up with the + // asterisk in the comment opener; otherwise, line up + // with the first character of the comment text. + if (done) + ; + else if (theline[0] == '*') + amount += 1; + else + { + // If we are more than one line away from the comment opener, take + // the indent of the previous non-empty line. If 'cino' has "CO" + // and we are just below the comment opener and there are any + // white characters after it line up with the text after it; + // otherwise, add the amount specified by "c" in 'cino' + amount = -1; + for (lnum = cur_curpos.lnum - 1; lnum > comment_pos->lnum; --lnum) + { + if (linewhite(lnum)) // skip blank lines + continue; + amount = get_indent_lnum(lnum); // XXX + break; + } + if (amount == -1) // use the comment opener + { + if (!curbuf->b_ind_in_comment2) + { + start = ml_get(comment_pos->lnum); + look = start + comment_pos->col + 2; // skip / and * + if (*look != NUL) // if something after it + comment_pos->col = (colnr_T)(skipwhite(look) - start); + } + getvcol(curwin, comment_pos, &col, NULL, NULL); + amount = col; + if (curbuf->b_ind_in_comment2 || *look == NUL) + amount += curbuf->b_ind_in_comment; + } + } + goto theend; + } + + // Are we looking at a ']' that has a match? + if (*skipwhite(theline) == ']' + && (trypos = find_match_char('[', curbuf->b_ind_maxparen)) != NULL) + { + // align with the line containing the '['. + amount = get_indent_lnum(trypos->lnum); + goto theend; + } + + // Are we inside parentheses or braces? XXX + if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL + && curbuf->b_ind_java == 0) + || (tryposBrace = find_start_brace()) != NULL + || trypos != NULL) + { + if (trypos != NULL && tryposBrace != NULL) + { + // Both an unmatched '(' and '{' is found. Use the one which is + // closer to the current cursor position, set the other to NULL. + if (trypos->lnum != tryposBrace->lnum + ? trypos->lnum < tryposBrace->lnum + : trypos->col < tryposBrace->col) + trypos = NULL; + else + tryposBrace = NULL; + } + + if (trypos != NULL) + { + // If the matching paren is more than one line away, use the indent of + // a previous non-empty line that matches the same paren. + if (theline[0] == ')' && curbuf->b_ind_paren_prev) + { + // Line up with the start of the matching paren line. + amount = get_indent_lnum(curwin->w_cursor.lnum - 1); // XXX + } + else + { + amount = -1; + our_paren_pos = *trypos; + for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum) + { + l = skipwhite(ml_get(lnum)); + if (cin_nocode(l)) // skip comment lines + continue; + if (cin_ispreproc_cont(&l, &lnum, &amount)) + continue; // ignore #define, #if, etc. + curwin->w_cursor.lnum = lnum; + + // Skip a comment or raw string. XXX + if ((trypos = ind_find_start_CORS(NULL)) != NULL) + { + lnum = trypos->lnum + 1; + continue; + } + + // XXX + if ((trypos = find_match_paren( + corr_ind_maxparen(&cur_curpos))) != NULL + && trypos->lnum == our_paren_pos.lnum + && trypos->col == our_paren_pos.col) + { + amount = get_indent_lnum(lnum); // XXX + + if (theline[0] == ')') + { + if (our_paren_pos.lnum != lnum + && cur_amount > amount) + cur_amount = amount; + amount = -1; + } + break; + } + } + } + + // Line up with line where the matching paren is. XXX + // If the line starts with a '(' or the indent for unclosed + // parentheses is zero, line up with the unclosed parentheses. + if (amount == -1) + { + int ignore_paren_col = 0; + int is_if_for_while = 0; + + if (curbuf->b_ind_if_for_while) + { + // Look for the outermost opening parenthesis on this line + // and check whether it belongs to an "if", "for" or "while". + + pos_T cursor_save = curwin->w_cursor; + pos_T outermost; + char_u *line; + + trypos = &our_paren_pos; + do { + outermost = *trypos; + curwin->w_cursor.lnum = outermost.lnum; + curwin->w_cursor.col = outermost.col; + + trypos = find_match_paren(curbuf->b_ind_maxparen); + } while (trypos && trypos->lnum == outermost.lnum); + + curwin->w_cursor = cursor_save; + + line = ml_get(outermost.lnum); + + is_if_for_while = + cin_is_if_for_while_before_offset(line, &outermost.col); + } + + amount = skip_label(our_paren_pos.lnum, &look); + look = skipwhite(look); + if (*look == '(') + { + linenr_T save_lnum = curwin->w_cursor.lnum; + char_u *line; + int look_col; + + // Ignore a '(' in front of the line that has a match before + // our matching '('. + curwin->w_cursor.lnum = our_paren_pos.lnum; + line = ml_get_curline(); + look_col = (int)(look - line); + curwin->w_cursor.col = look_col + 1; + if ((trypos = findmatchlimit(NULL, ')', 0, + curbuf->b_ind_maxparen)) + != NULL + && trypos->lnum == our_paren_pos.lnum + && trypos->col < our_paren_pos.col) + ignore_paren_col = trypos->col + 1; + + curwin->w_cursor.lnum = save_lnum; + look = ml_get(our_paren_pos.lnum) + look_col; + } + if (theline[0] == ')' || (curbuf->b_ind_unclosed == 0 + && is_if_for_while == 0) + || (!curbuf->b_ind_unclosed_noignore && *look == '(' + && ignore_paren_col == 0)) + { + // If we're looking at a close paren, line up right there; + // otherwise, line up with the next (non-white) character. + // When b_ind_unclosed_wrapped is set and the matching paren is + // the last nonwhite character of the line, use either the + // indent of the current line or the indentation of the next + // outer paren and add b_ind_unclosed_wrapped (for very long + // lines). + if (theline[0] != ')') + { + cur_amount = MAXCOL; + l = ml_get(our_paren_pos.lnum); + if (curbuf->b_ind_unclosed_wrapped + && cin_ends_in(l, (char_u *)"(", NULL)) + { + // look for opening unmatched paren, indent one level + // for each additional level + n = 1; + for (col = 0; col < our_paren_pos.col; ++col) + { + switch (l[col]) + { + case '(': + case '{': ++n; + break; + + case ')': + case '}': if (n > 1) + --n; + break; + } + } + + our_paren_pos.col = 0; + amount += n * curbuf->b_ind_unclosed_wrapped; + } + else if (curbuf->b_ind_unclosed_whiteok) + our_paren_pos.col++; + else + { + col = our_paren_pos.col + 1; + while (VIM_ISWHITE(l[col])) + col++; + if (l[col] != NUL) // In case of trailing space + our_paren_pos.col = col; + else + our_paren_pos.col++; + } + } + + // Find how indented the paren is, or the character after it + // if we did the above "if". + if (our_paren_pos.col > 0) + { + getvcol(curwin, &our_paren_pos, &col, NULL, NULL); + if (cur_amount > (int)col) + cur_amount = col; + } + } + + if (theline[0] == ')' && curbuf->b_ind_matching_paren) + { + // Line up with the start of the matching paren line. + } + else if ((curbuf->b_ind_unclosed == 0 && is_if_for_while == 0) + || (!curbuf->b_ind_unclosed_noignore + && *look == '(' && ignore_paren_col == 0)) + { + if (cur_amount != MAXCOL) + amount = cur_amount; + } + else + { + // Add b_ind_unclosed2 for each '(' before our matching one, + // but ignore (void) before the line (ignore_paren_col). + col = our_paren_pos.col; + while ((int)our_paren_pos.col > ignore_paren_col) + { + --our_paren_pos.col; + switch (*ml_get_pos(&our_paren_pos)) + { + case '(': amount += curbuf->b_ind_unclosed2; + col = our_paren_pos.col; + break; + case ')': amount -= curbuf->b_ind_unclosed2; + col = MAXCOL; + break; + } + } + + // Use b_ind_unclosed once, when the first '(' is not inside + // braces + if (col == MAXCOL) + amount += curbuf->b_ind_unclosed; + else + { + curwin->w_cursor.lnum = our_paren_pos.lnum; + curwin->w_cursor.col = col; + if (find_match_paren_after_brace(curbuf->b_ind_maxparen) + != NULL) + amount += curbuf->b_ind_unclosed2; + else + { + if (is_if_for_while) + amount += curbuf->b_ind_if_for_while; + else + amount += curbuf->b_ind_unclosed; + } + } + // For a line starting with ')' use the minimum of the two + // positions, to avoid giving it more indent than the previous + // lines: + // func_long_name( if (x + // arg && yy + // ) ^ not here ) ^ not here + if (cur_amount < amount) + amount = cur_amount; + } + } + + // add extra indent for a comment + if (cin_iscomment(theline)) + amount += curbuf->b_ind_comment; + } + else + { + // We are inside braces, there is a { before this line at the position + // stored in tryposBrace. + // Make a copy of tryposBrace, it may point to pos_copy inside + // find_start_brace(), which may be changed somewhere. + tryposCopy = *tryposBrace; + tryposBrace = &tryposCopy; + trypos = tryposBrace; + ourscope = trypos->lnum; + start = ml_get(ourscope); + + // Now figure out how indented the line is in general. + // If the brace was at the start of the line, we use that; + // otherwise, check out the indentation of the line as + // a whole and then add the "imaginary indent" to that. + look = skipwhite(start); + if (*look == '{') + { + getvcol(curwin, trypos, &col, NULL, NULL); + amount = col; + if (*start == '{') + start_brace = BRACE_IN_COL0; + else + start_brace = BRACE_AT_START; + } + else + { + // That opening brace might have been on a continuation + // line. if so, find the start of the line. + curwin->w_cursor.lnum = ourscope; + + // Position the cursor over the rightmost paren, so that + // matching it will take us back to the start of the line. + lnum = ourscope; + if (find_last_paren(start, '(', ')') + && (trypos = find_match_paren(curbuf->b_ind_maxparen)) + != NULL) + lnum = trypos->lnum; + + // It could have been something like + // case 1: if (asdf && + // condition) { + // } + if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label) + && cin_iscase(skipwhite(ml_get_curline()), FALSE)) + amount = get_indent(); + else if (curbuf->b_ind_js) + amount = get_indent_lnum(lnum); + else + amount = skip_label(lnum, &l); + + start_brace = BRACE_AT_END; + } + + // For Javascript check if the line starts with "key:". + if (curbuf->b_ind_js) + js_cur_has_key = cin_has_js_key(theline); + + // If we're looking at a closing brace, that's where + // we want to be. otherwise, add the amount of room + // that an indent is supposed to be. + if (theline[0] == '}') + { + // they may want closing braces to line up with something + // other than the open brace. indulge them, if so. + amount += curbuf->b_ind_close_extra; + } + else + { + // If we're looking at an "else", try to find an "if" + // to match it with. + // If we're looking at a "while", try to find a "do" + // to match it with. + lookfor = LOOKFOR_INITIAL; + if (cin_iselse(theline)) + lookfor = LOOKFOR_IF; + else if (cin_iswhileofdo(theline, cur_curpos.lnum)) // XXX + lookfor = LOOKFOR_DO; + if (lookfor != LOOKFOR_INITIAL) + { + curwin->w_cursor.lnum = cur_curpos.lnum; + if (find_match(lookfor, ourscope) == OK) + { + amount = get_indent(); // XXX + goto theend; + } + } + + // We get here if we are not on an "while-of-do" or "else" (or + // failed to find a matching "if"). + // Search backwards for something to line up with. + // First set amount for when we don't find anything. + + // if the '{' is _really_ at the left margin, use the imaginary + // location of a left-margin brace. Otherwise, correct the + // location for b_ind_open_extra. + + if (start_brace == BRACE_IN_COL0) // '{' is in column 0 + { + amount = curbuf->b_ind_open_left_imag; + lookfor_cpp_namespace = TRUE; + } + else if (start_brace == BRACE_AT_START && + lookfor_cpp_namespace) // '{' is at start + { + + lookfor_cpp_namespace = TRUE; + } + else + { + if (start_brace == BRACE_AT_END) // '{' is at end of line + { + amount += curbuf->b_ind_open_imag; + + l = skipwhite(ml_get_curline()); + if (cin_is_cpp_namespace(l)) + amount += curbuf->b_ind_cpp_namespace; + else if (cin_is_cpp_extern_c(l)) + amount += curbuf->b_ind_cpp_extern_c; + } + else + { + // Compensate for adding b_ind_open_extra later. + amount -= curbuf->b_ind_open_extra; + if (amount < 0) + amount = 0; + } + } + + lookfor_break = FALSE; + + if (cin_iscase(theline, FALSE)) // it's a switch() label + { + lookfor = LOOKFOR_CASE; // find a previous switch() label + amount += curbuf->b_ind_case; + } + else if (cin_isscopedecl(theline)) // private:, ... + { + lookfor = LOOKFOR_SCOPEDECL; // class decl is this block + amount += curbuf->b_ind_scopedecl; + } + else + { + if (curbuf->b_ind_case_break && cin_isbreak(theline)) + // break; ... + lookfor_break = TRUE; + + lookfor = LOOKFOR_INITIAL; + // b_ind_level from start of block + amount += curbuf->b_ind_level; + } + scope_amount = amount; + whilelevel = 0; + + // Search backwards. If we find something we recognize, line up + // with that. + // + // If we're looking at an open brace, indent + // the usual amount relative to the conditional + // that opens the block. + curwin->w_cursor = cur_curpos; + for (;;) + { + curwin->w_cursor.lnum--; + curwin->w_cursor.col = 0; + + // If we went all the way back to the start of our scope, line + // up with it. + if (curwin->w_cursor.lnum <= ourscope) + { + // We reached end of scope: + // If looking for an enum or structure initialization + // go further back: + // If it is an initializer (enum xxx or xxx =), then + // don't add ind_continuation, otherwise it is a variable + // declaration: + // int x, + // here; <-- add ind_continuation + if (lookfor == LOOKFOR_ENUM_OR_INIT) + { + if (curwin->w_cursor.lnum == 0 + || curwin->w_cursor.lnum + < ourscope - curbuf->b_ind_maxparen) + { + // nothing found (abuse curbuf->b_ind_maxparen as + // limit) assume terminated line (i.e. a variable + // initialization) + if (cont_amount > 0) + amount = cont_amount; + else if (!curbuf->b_ind_js) + amount += ind_continuation; + break; + } + + // If we're in a comment or raw string now, skip to + // the start of it. + trypos = ind_find_start_CORS(NULL); + if (trypos != NULL) + { + curwin->w_cursor.lnum = trypos->lnum + 1; + curwin->w_cursor.col = 0; + continue; + } + + l = ml_get_curline(); + + // Skip preprocessor directives and blank lines. + if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, + &amount)) + continue; + + if (cin_nocode(l)) + continue; + + terminated = cin_isterminated(l, FALSE, TRUE); + + // If we are at top level and the line looks like a + // function declaration, we are done + // (it's a variable declaration). + if (start_brace != BRACE_IN_COL0 + || !cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0)) + { + // if the line is terminated with another ',' + // it is a continued variable initialization. + // don't add extra indent. + // TODO: does not work, if a function + // declaration is split over multiple lines: + // cin_isfuncdecl returns FALSE then. + if (terminated == ',') + break; + + // if it is an enum declaration or an assignment, + // we are done. + if (terminated != ';' && cin_isinit()) + break; + + // nothing useful found + if (terminated == 0 || terminated == '{') + continue; + } + + if (terminated != ';') + { + // Skip parens and braces. Position the cursor + // over the rightmost paren, so that matching it + // will take us back to the start of the line. + // XXX + trypos = NULL; + if (find_last_paren(l, '(', ')')) + trypos = find_match_paren( + curbuf->b_ind_maxparen); + + if (trypos == NULL && find_last_paren(l, '{', '}')) + trypos = find_start_brace(); + + if (trypos != NULL) + { + curwin->w_cursor.lnum = trypos->lnum + 1; + curwin->w_cursor.col = 0; + continue; + } + } + + // it's a variable declaration, add indentation + // like in + // int a, + // b; + if (cont_amount > 0) + amount = cont_amount; + else + amount += ind_continuation; + } + else if (lookfor == LOOKFOR_UNTERM) + { + if (cont_amount > 0) + amount = cont_amount; + else + amount += ind_continuation; + } + else + { + if (lookfor != LOOKFOR_TERM + && lookfor != LOOKFOR_CPP_BASECLASS + && lookfor != LOOKFOR_COMMA) + { + amount = scope_amount; + if (theline[0] == '{') + { + amount += curbuf->b_ind_open_extra; + added_to_amount = curbuf->b_ind_open_extra; + } + } + + if (lookfor_cpp_namespace) + { + // Looking for C++ namespace, need to look further + // back. + if (curwin->w_cursor.lnum == ourscope) + continue; + + if (curwin->w_cursor.lnum == 0 + || curwin->w_cursor.lnum + < ourscope - FIND_NAMESPACE_LIM) + break; + + // If we're in a comment or raw string now, skip + // to the start of it. + trypos = ind_find_start_CORS(NULL); + if (trypos != NULL) + { + curwin->w_cursor.lnum = trypos->lnum + 1; + curwin->w_cursor.col = 0; + continue; + } + + l = ml_get_curline(); + + // Skip preprocessor directives and blank lines. + if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, + &amount)) + continue; + + // Finally the actual check for "namespace". + if (cin_is_cpp_namespace(l)) + { + amount += curbuf->b_ind_cpp_namespace + - added_to_amount; + break; + } + else if (cin_is_cpp_extern_c(l)) + { + amount += curbuf->b_ind_cpp_extern_c + - added_to_amount; + break; + } + + if (cin_nocode(l)) + continue; + } + } + break; + } + + // If we're in a comment or raw string now, skip to the start + // of it. XXX + if ((trypos = ind_find_start_CORS(&raw_string_start)) != NULL) + { + curwin->w_cursor.lnum = trypos->lnum + 1; + curwin->w_cursor.col = 0; + continue; + } + + l = ml_get_curline(); + + // If this is a switch() label, may line up relative to that. + // If this is a C++ scope declaration, do the same. + iscase = cin_iscase(l, FALSE); + if (iscase || cin_isscopedecl(l)) + { + // we are only looking for cpp base class + // declaration/initialization any longer + if (lookfor == LOOKFOR_CPP_BASECLASS) + break; + + // When looking for a "do" we are not interested in + // labels. + if (whilelevel > 0) + continue; + + // case xx: + // c = 99 + <- this indent plus continuation + //-> here; + if (lookfor == LOOKFOR_UNTERM + || lookfor == LOOKFOR_ENUM_OR_INIT) + { + if (cont_amount > 0) + amount = cont_amount; + else + amount += ind_continuation; + break; + } + + // case xx: <- line up with this case + // x = 333; + // case yy: + if ( (iscase && lookfor == LOOKFOR_CASE) + || (iscase && lookfor_break) + || (!iscase && lookfor == LOOKFOR_SCOPEDECL)) + { + // Check that this case label is not for another + // switch() XXX + if ((trypos = find_start_brace()) == NULL + || trypos->lnum == ourscope) + { + amount = get_indent(); // XXX + break; + } + continue; + } + + n = get_indent_nolabel(curwin->w_cursor.lnum); // XXX + + // case xx: if (cond) <- line up with this if + // y = y + 1; + // -> s = 99; + // + // case xx: + // if (cond) <- line up with this line + // y = y + 1; + // -> s = 99; + if (lookfor == LOOKFOR_TERM) + { + if (n) + amount = n; + + if (!lookfor_break) + break; + } + + // case xx: x = x + 1; <- line up with this x + // -> y = y + 1; + // + // case xx: if (cond) <- line up with this if + // -> y = y + 1; + if (n) + { + amount = n; + l = after_label(ml_get_curline()); + if (l != NULL && cin_is_cinword(l)) + { + if (theline[0] == '{') + amount += curbuf->b_ind_open_extra; + else + amount += curbuf->b_ind_level + + curbuf->b_ind_no_brace; + } + break; + } + + // Try to get the indent of a statement before the switch + // label. If nothing is found, line up relative to the + // switch label. + // break; <- may line up with this line + // case xx: + // -> y = 1; + scope_amount = get_indent() + (iscase // XXX + ? curbuf->b_ind_case_code + : curbuf->b_ind_scopedecl_code); + lookfor = curbuf->b_ind_case_break + ? LOOKFOR_NOBREAK : LOOKFOR_ANY; + continue; + } + + // Looking for a switch() label or C++ scope declaration, + // ignore other lines, skip {}-blocks. + if (lookfor == LOOKFOR_CASE || lookfor == LOOKFOR_SCOPEDECL) + { + if (find_last_paren(l, '{', '}') + && (trypos = find_start_brace()) != NULL) + { + curwin->w_cursor.lnum = trypos->lnum + 1; + curwin->w_cursor.col = 0; + } + continue; + } + + // Ignore jump labels with nothing after them. + if (!curbuf->b_ind_js && cin_islabel()) + { + l = after_label(ml_get_curline()); + if (l == NULL || cin_nocode(l)) + continue; + } + + // Ignore #defines, #if, etc. + // Ignore comment and empty lines. + // (need to get the line again, cin_islabel() may have + // unlocked it) + l = ml_get_curline(); + if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount) + || cin_nocode(l)) + continue; + + // Are we at the start of a cpp base class declaration or + // constructor initialization? XXX + n = FALSE; + if (lookfor != LOOKFOR_TERM && curbuf->b_ind_cpp_baseclass > 0) + { + n = cin_is_cpp_baseclass(&cache_cpp_baseclass); + l = ml_get_curline(); + } + if (n) + { + if (lookfor == LOOKFOR_UNTERM) + { + if (cont_amount > 0) + amount = cont_amount; + else + amount += ind_continuation; + } + else if (theline[0] == '{') + { + // Need to find start of the declaration. + lookfor = LOOKFOR_UNTERM; + ind_continuation = 0; + continue; + } + else + // XXX + amount = get_baseclass_amount( + cache_cpp_baseclass.lpos.col); + break; + } + else if (lookfor == LOOKFOR_CPP_BASECLASS) + { + // only look, whether there is a cpp base class + // declaration or initialization before the opening brace. + if (cin_isterminated(l, TRUE, FALSE)) + break; + else + continue; + } + + // What happens next depends on the line being terminated. + // If terminated with a ',' only consider it terminating if + // there is another unterminated statement behind, eg: + // 123, + // sizeof + // here + // Otherwise check whether it is an enumeration or structure + // initialisation (not indented) or a variable declaration + // (indented). + terminated = cin_isterminated(l, FALSE, TRUE); + + if (js_cur_has_key) + { + js_cur_has_key = 0; // only check the first line + if (curbuf->b_ind_js && terminated == ',') + { + // For Javascript we might be inside an object: + // key: something, <- align with this + // key: something + // or: + // key: something + <- align with this + // something, + // key: something + lookfor = LOOKFOR_JS_KEY; + } + } + if (lookfor == LOOKFOR_JS_KEY && cin_has_js_key(l)) + { + amount = get_indent(); + break; + } + if (lookfor == LOOKFOR_COMMA) + { + if (tryposBrace != NULL && tryposBrace->lnum + >= curwin->w_cursor.lnum) + break; + if (terminated == ',') + // line below current line is the one that starts a + // (possibly broken) line ending in a comma. + break; + else + { + amount = get_indent(); + if (curwin->w_cursor.lnum - 1 == ourscope) + // line above is start of the scope, thus current + // line is the one that stars a (possibly broken) + // line ending in a comma. + break; + } + } + + if (terminated == 0 || (lookfor != LOOKFOR_UNTERM + && terminated == ',')) + { + if (lookfor != LOOKFOR_ENUM_OR_INIT && + (*skipwhite(l) == '[' || l[STRLEN(l) - 1] == '[')) + amount += ind_continuation; + // if we're in the middle of a paren thing, + // go back to the line that starts it so + // we can get the right prevailing indent + // if ( foo && + // bar ) + + // Position the cursor over the rightmost paren, so that + // matching it will take us back to the start of the line. + // Ignore a match before the start of the block. + (void)find_last_paren(l, '(', ')'); + trypos = find_match_paren(corr_ind_maxparen(&cur_curpos)); + if (trypos != NULL && (trypos->lnum < tryposBrace->lnum + || (trypos->lnum == tryposBrace->lnum + && trypos->col < tryposBrace->col))) + trypos = NULL; + + l = ml_get_curline(); + + // If we are looking for ',', we also look for matching + // braces. + if (trypos == NULL && terminated == ',') + { + if (find_last_paren(l, '{', '}')) + trypos = find_start_brace(); + l = ml_get_curline(); + } + + if (trypos != NULL) + { + // Check if we are on a case label now. This is + // handled above. + // case xx: if ( asdf && + // asdf) + curwin->w_cursor = *trypos; + l = ml_get_curline(); + if (cin_iscase(l, FALSE) || cin_isscopedecl(l)) + { + ++curwin->w_cursor.lnum; + curwin->w_cursor.col = 0; + continue; + } + } + + // Skip over continuation lines to find the one to get the + // indent from + // char *usethis = "bla{backslash} + // bla", + // here; + if (terminated == ',') + { + while (curwin->w_cursor.lnum > 1) + { + l = ml_get(curwin->w_cursor.lnum - 1); + if (*l == NUL || l[STRLEN(l) - 1] != '\\') + break; + --curwin->w_cursor.lnum; + curwin->w_cursor.col = 0; + } + l = ml_get_curline(); + } + + // Get indent and pointer to text for current line, + // ignoring any jump label. XXX + if (curbuf->b_ind_js) + cur_amount = get_indent(); + else + cur_amount = skip_label(curwin->w_cursor.lnum, &l); + // If this is just above the line we are indenting, and it + // starts with a '{', line it up with this line. + // while (not) + // -> { + // } + if (terminated != ',' && lookfor != LOOKFOR_TERM + && theline[0] == '{') + { + amount = cur_amount; + // Only add b_ind_open_extra when the current line + // doesn't start with a '{', which must have a match + // in the same line (scope is the same). Probably: + // { 1, 2 }, + // -> { 3, 4 } + if (*skipwhite(l) != '{') + amount += curbuf->b_ind_open_extra; + + if (curbuf->b_ind_cpp_baseclass && !curbuf->b_ind_js) + { + // have to look back, whether it is a cpp base + // class declaration or initialization + lookfor = LOOKFOR_CPP_BASECLASS; + continue; + } + break; + } + + // Check if we are after an "if", "while", etc. + // Also allow "} else". + if (cin_is_cinword(l) || cin_iselse(skipwhite(l))) + { + // Found an unterminated line after an if (), line up + // with the last one. + // if (cond) + // 100 + + // -> here; + if (lookfor == LOOKFOR_UNTERM + || lookfor == LOOKFOR_ENUM_OR_INIT) + { + if (cont_amount > 0) + amount = cont_amount; + else + amount += ind_continuation; + break; + } + + // If this is just above the line we are indenting, we + // are finished. + // while (not) + // -> here; + // Otherwise this indent can be used when the line + // before this is terminated. + // yyy; + // if (stat) + // while (not) + // xxx; + // -> here; + amount = cur_amount; + if (theline[0] == '{') + amount += curbuf->b_ind_open_extra; + if (lookfor != LOOKFOR_TERM) + { + amount += curbuf->b_ind_level + + curbuf->b_ind_no_brace; + break; + } + + // Special trick: when expecting the while () after a + // do, line up with the while() + // do + // x = 1; + // -> here + l = skipwhite(ml_get_curline()); + if (cin_isdo(l)) + { + if (whilelevel == 0) + break; + --whilelevel; + } + + // When searching for a terminated line, don't use the + // one between the "if" and the matching "else". + // Need to use the scope of this "else". XXX + // If whilelevel != 0 continue looking for a "do {". + if (cin_iselse(l) && whilelevel == 0) + { + // If we're looking at "} else", let's make sure we + // find the opening brace of the enclosing scope, + // not the one from "if (condition) {". + if (*l == '}') + curwin->w_cursor.col = + (colnr_T)(l - ml_get_curline()) + 1; + + if ((trypos = find_start_brace()) == NULL + || find_match(LOOKFOR_IF, trypos->lnum) + == FAIL) + break; + } + } + + // If we're below an unterminated line that is not an + // "if" or something, we may line up with this line or + // add something for a continuation line, depending on + // the line before this one. + else + { + // Found two unterminated lines on a row, line up with + // the last one. + // c = 99 + + // 100 + + // -> here; + if (lookfor == LOOKFOR_UNTERM) + { + // When line ends in a comma add extra indent + if (terminated == ',') + amount += ind_continuation; + break; + } + + if (lookfor == LOOKFOR_ENUM_OR_INIT) + { + // Found two lines ending in ',', lineup with the + // lowest one, but check for cpp base class + // declaration/initialization, if it is an + // opening brace or we are looking just for + // enumerations/initializations. + if (terminated == ',') + { + if (curbuf->b_ind_cpp_baseclass == 0) + break; + + lookfor = LOOKFOR_CPP_BASECLASS; + continue; + } + + // Ignore unterminated lines in between, but + // reduce indent. + if (amount > cur_amount) + amount = cur_amount; + } + else + { + // Found first unterminated line on a row, may + // line up with this line, remember its indent + // 100 + + // -> here; + l = ml_get_curline(); + amount = cur_amount; + + n = (int)STRLEN(l); + if (terminated == ',' && (*skipwhite(l) == ']' + || (n >=2 && l[n - 2] == ']'))) + break; + + // If previous line ends in ',', check whether we + // are in an initialization or enum + // struct xxx = + // { + // sizeof a, + // 124 }; + // or a normal possible continuation line. + // but only, of no other statement has been found + // yet. + if (lookfor == LOOKFOR_INITIAL && terminated == ',') + { + if (curbuf->b_ind_js) + { + // Search for a line ending in a comma + // and line up with the line below it + // (could be the current line). + // some = [ + // 1, <- line up here + // 2, + // some = [ + // 3 + <- line up here + // 4 * + // 5, + // 6, + if (cin_iscomment(skipwhite(l))) + break; + lookfor = LOOKFOR_COMMA; + trypos = find_match_char('[', + curbuf->b_ind_maxparen); + if (trypos != NULL) + { + if (trypos->lnum + == curwin->w_cursor.lnum - 1) + { + // Current line is first inside + // [], line up with it. + break; + } + ourscope = trypos->lnum; + } + } + else + { + lookfor = LOOKFOR_ENUM_OR_INIT; + cont_amount = cin_first_id_amount(); + } + } + else + { + if (lookfor == LOOKFOR_INITIAL + && *l != NUL + && l[STRLEN(l) - 1] == '\\') + // XXX + cont_amount = cin_get_equal_amount( + curwin->w_cursor.lnum); + if (lookfor != LOOKFOR_TERM + && lookfor != LOOKFOR_JS_KEY + && lookfor != LOOKFOR_COMMA + && raw_string_start != curwin->w_cursor.lnum) + lookfor = LOOKFOR_UNTERM; + } + } + } + } + + // Check if we are after a while (cond); + // If so: Ignore until the matching "do". + else if (cin_iswhileofdo_end(terminated)) // XXX + { + // Found an unterminated line after a while ();, line up + // with the last one. + // while (cond); + // 100 + <- line up with this one + // -> here; + if (lookfor == LOOKFOR_UNTERM + || lookfor == LOOKFOR_ENUM_OR_INIT) + { + if (cont_amount > 0) + amount = cont_amount; + else + amount += ind_continuation; + break; + } + + if (whilelevel == 0) + { + lookfor = LOOKFOR_TERM; + amount = get_indent(); // XXX + if (theline[0] == '{') + amount += curbuf->b_ind_open_extra; + } + ++whilelevel; + } + + // We are after a "normal" statement. + // If we had another statement we can stop now and use the + // indent of that other statement. + // Otherwise the indent of the current statement may be used, + // search backwards for the next "normal" statement. + else + { + // Skip single break line, if before a switch label. It + // may be lined up with the case label. + if (lookfor == LOOKFOR_NOBREAK + && cin_isbreak(skipwhite(ml_get_curline()))) + { + lookfor = LOOKFOR_ANY; + continue; + } + + // Handle "do {" line. + if (whilelevel > 0) + { + l = cin_skipcomment(ml_get_curline()); + if (cin_isdo(l)) + { + amount = get_indent(); // XXX + --whilelevel; + continue; + } + } + + // Found a terminated line above an unterminated line. Add + // the amount for a continuation line. + // x = 1; + // y = foo + + // -> here; + // or + // int x = 1; + // int foo, + // -> here; + if (lookfor == LOOKFOR_UNTERM + || lookfor == LOOKFOR_ENUM_OR_INIT) + { + if (cont_amount > 0) + amount = cont_amount; + else + amount += ind_continuation; + break; + } + + // Found a terminated line above a terminated line or "if" + // etc. line. Use the amount of the line below us. + // x = 1; x = 1; + // if (asdf) y = 2; + // while (asdf) ->here; + // here; + // ->foo; + if (lookfor == LOOKFOR_TERM) + { + if (!lookfor_break && whilelevel == 0) + break; + } + + // First line above the one we're indenting is terminated. + // To know what needs to be done look further backward for + // a terminated line. + else + { + // position the cursor over the rightmost paren, so + // that matching it will take us back to the start of + // the line. Helps for: + // func(asdr, + // asdfasdf); + // here; +term_again: + l = ml_get_curline(); + if (find_last_paren(l, '(', ')') + && (trypos = find_match_paren( + curbuf->b_ind_maxparen)) != NULL) + { + // Check if we are on a case label now. This is + // handled above. + // case xx: if ( asdf && + // asdf) + curwin->w_cursor = *trypos; + l = ml_get_curline(); + if (cin_iscase(l, FALSE) || cin_isscopedecl(l)) + { + ++curwin->w_cursor.lnum; + curwin->w_cursor.col = 0; + continue; + } + } + + // When aligning with the case statement, don't align + // with a statement after it. + // case 1: { <-- don't use this { position + // stat; + // } + // case 2: + // stat; + // } + iscase = (curbuf->b_ind_keep_case_label + && cin_iscase(l, FALSE)); + + // Get indent and pointer to text for current line, + // ignoring any jump label. + amount = skip_label(curwin->w_cursor.lnum, &l); + + if (theline[0] == '{') + amount += curbuf->b_ind_open_extra; + // See remark above: "Only add b_ind_open_extra.." + l = skipwhite(l); + if (*l == '{') + amount -= curbuf->b_ind_open_extra; + lookfor = iscase ? LOOKFOR_ANY : LOOKFOR_TERM; + + // When a terminated line starts with "else" skip to + // the matching "if": + // else 3; + // indent this; + // Need to use the scope of this "else". XXX + // If whilelevel != 0 continue looking for a "do {". + if (lookfor == LOOKFOR_TERM + && *l != '}' + && cin_iselse(l) + && whilelevel == 0) + { + if ((trypos = find_start_brace()) == NULL + || find_match(LOOKFOR_IF, trypos->lnum) + == FAIL) + break; + continue; + } + + // If we're at the end of a block, skip to the start of + // that block. + l = ml_get_curline(); + if (find_last_paren(l, '{', '}') // XXX + && (trypos = find_start_brace()) != NULL) + { + curwin->w_cursor = *trypos; + // if not "else {" check for terminated again + // but skip block for "} else {" + l = cin_skipcomment(ml_get_curline()); + if (*l == '}' || !cin_iselse(l)) + goto term_again; + ++curwin->w_cursor.lnum; + curwin->w_cursor.col = 0; + } + } + } + } + } + } + + // add extra indent for a comment + if (cin_iscomment(theline)) + amount += curbuf->b_ind_comment; + + // subtract extra left-shift for jump labels + if (curbuf->b_ind_jump_label > 0 && original_line_islabel) + amount -= curbuf->b_ind_jump_label; + + goto theend; + } + + // ok -- we're not inside any sort of structure at all! + // + // This means we're at the top level, and everything should + // basically just match where the previous line is, except + // for the lines immediately following a function declaration, + // which are K&R-style parameters and need to be indented. + // + // if our line starts with an open brace, forget about any + // prevailing indent and make sure it looks like the start + // of a function + + if (theline[0] == '{') + { + amount = curbuf->b_ind_first_open; + goto theend; + } + + // If the NEXT line is a function declaration, the current + // line needs to be indented as a function type spec. + // Don't do this if the current line looks like a comment or if the + // current line is terminated, ie. ends in ';', or if the current line + // contains { or }: "void f(condition) {\n if (1)" + if (cur_curpos.lnum < curbuf->b_ml.ml_line_count + && !cin_nocode(theline) + && vim_strchr(theline, '{') == NULL + && vim_strchr(theline, '}') == NULL + && !cin_ends_in(theline, (char_u *)":", NULL) + && !cin_ends_in(theline, (char_u *)",", NULL) + && cin_isfuncdecl(NULL, cur_curpos.lnum + 1, + cur_curpos.lnum + 1) + && !cin_isterminated(theline, FALSE, TRUE)) + { + amount = curbuf->b_ind_func_type; + goto theend; + } + + // search backwards until we find something we recognize + amount = 0; + curwin->w_cursor = cur_curpos; + while (curwin->w_cursor.lnum > 1) + { + curwin->w_cursor.lnum--; + curwin->w_cursor.col = 0; + + l = ml_get_curline(); + + // If we're in a comment or raw string now, skip to the start + // of it. XXX + if ((trypos = ind_find_start_CORS(NULL)) != NULL) + { + curwin->w_cursor.lnum = trypos->lnum + 1; + curwin->w_cursor.col = 0; + continue; + } + + // Are we at the start of a cpp base class declaration or + // constructor initialization? XXX + n = FALSE; + if (curbuf->b_ind_cpp_baseclass != 0) + { + n = cin_is_cpp_baseclass(&cache_cpp_baseclass); + l = ml_get_curline(); + } + if (n) + { + // XXX + amount = get_baseclass_amount(cache_cpp_baseclass.lpos.col); + break; + } + + // Skip preprocessor directives and blank lines. + if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)) + continue; + + if (cin_nocode(l)) + continue; + + // If the previous line ends in ',', use one level of + // indentation: + // int foo, + // bar; + // do this before checking for '}' in case of eg. + // enum foobar + // { + // ... + // } foo, + // bar; + n = 0; + if (cin_ends_in(l, (char_u *)",", NULL) + || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\')) + { + // take us back to opening paren + if (find_last_paren(l, '(', ')') + && (trypos = find_match_paren( + curbuf->b_ind_maxparen)) != NULL) + curwin->w_cursor = *trypos; + + // For a line ending in ',' that is a continuation line go + // back to the first line with a backslash: + // char *foo = "bla{backslash} + // bla", + // here; + while (n == 0 && curwin->w_cursor.lnum > 1) + { + l = ml_get(curwin->w_cursor.lnum - 1); + if (*l == NUL || l[STRLEN(l) - 1] != '\\') + break; + --curwin->w_cursor.lnum; + curwin->w_cursor.col = 0; + } + + amount = get_indent(); // XXX + + if (amount == 0) + amount = cin_first_id_amount(); + if (amount == 0) + amount = ind_continuation; + break; + } + + // If the line looks like a function declaration, and we're + // not in a comment, put it the left margin. + if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0)) // XXX + break; + l = ml_get_curline(); + + // Finding the closing '}' of a previous function. Put + // current line at the left margin. For when 'cino' has "fs". + if (*skipwhite(l) == '}') + break; + + // (matching {) + // If the previous line ends on '};' (maybe followed by + // comments) align at column 0. For example: + // char *string_array[] = { "foo", + // / * x * / "b};ar" }; / * foobar * / + if (cin_ends_in(l, (char_u *)"};", NULL)) + break; + + // If the previous line ends on '[' we are probably in an + // array constant: + // something = [ + // 234, <- extra indent + if (cin_ends_in(l, (char_u *)"[", NULL)) + { + amount = get_indent() + ind_continuation; + break; + } + + // Find a line only has a semicolon that belongs to a previous + // line ending in '}', e.g. before an #endif. Don't increase + // indent then. + if (*(look = skipwhite(l)) == ';' && cin_nocode(look + 1)) + { + pos_T curpos_save = curwin->w_cursor; + + while (curwin->w_cursor.lnum > 1) + { + look = ml_get(--curwin->w_cursor.lnum); + if (!(cin_nocode(look) || cin_ispreproc_cont( + &look, &curwin->w_cursor.lnum, &amount))) + break; + } + if (curwin->w_cursor.lnum > 0 + && cin_ends_in(look, (char_u *)"}", NULL)) + break; + + curwin->w_cursor = curpos_save; + } + + // If the PREVIOUS line is a function declaration, the current + // line (and the ones that follow) needs to be indented as + // parameters. + if (cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0)) + { + amount = curbuf->b_ind_param; + break; + } + + // If the previous line ends in ';' and the line before the + // previous line ends in ',' or '\', ident to column zero: + // int foo, + // bar; + // indent_to_0 here; + if (cin_ends_in(l, (char_u *)";", NULL)) + { + l = ml_get(curwin->w_cursor.lnum - 1); + if (cin_ends_in(l, (char_u *)",", NULL) + || (*l != NUL && l[STRLEN(l) - 1] == '\\')) + break; + l = ml_get_curline(); + } + + // Doesn't look like anything interesting -- so just + // use the indent of this line. + // + // Position the cursor over the rightmost paren, so that + // matching it will take us back to the start of the line. + find_last_paren(l, '(', ')'); + + if ((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) + curwin->w_cursor = *trypos; + amount = get_indent(); // XXX + break; + } + + // add extra indent for a comment + if (cin_iscomment(theline)) + amount += curbuf->b_ind_comment; + + // add extra indent if the previous line ended in a backslash: + // "asdfasdf{backslash} + // here"; + // char *foo = "asdf{backslash} + // here"; + if (cur_curpos.lnum > 1) + { + l = ml_get(cur_curpos.lnum - 1); + if (*l != NUL && l[STRLEN(l) - 1] == '\\') + { + cur_amount = cin_get_equal_amount(cur_curpos.lnum - 1); + if (cur_amount > 0) + amount = cur_amount; + else if (cur_amount == 0) + amount += ind_continuation; + } + } + +theend: + if (amount < 0) + amount = 0; + +laterend: + // put the cursor back where it belongs + curwin->w_cursor = cur_curpos; + + vim_free(linecopy); + + return amount; +} + +/* + * return TRUE if 'cinkeys' contains the key "keytyped", + * when == '*': Only if key is preceded with '*' (indent before insert) + * when == '!': Only if key is preceded with '!' (don't insert) + * when == ' ': Only if key is not preceded with '*'(indent afterwards) + * + * "keytyped" can have a few special values: + * KEY_OPEN_FORW + * KEY_OPEN_BACK + * KEY_COMPLETE just finished completion. + * + * If line_is_empty is TRUE accept keys with '0' before them. + */ + int +in_cinkeys( + int keytyped, + int when, + int line_is_empty) +{ + char_u *look; + int try_match; + int try_match_word; + char_u *p; + char_u *line; + int icase; + int i; + + if (keytyped == NUL) + // Can happen with CTRL-Y and CTRL-E on a short line. + return FALSE; + +#ifdef FEAT_EVAL + if (*curbuf->b_p_inde != NUL) + look = curbuf->b_p_indk; // 'indentexpr' set: use 'indentkeys' + else +#endif + look = curbuf->b_p_cink; // 'indentexpr' empty: use 'cinkeys' + while (*look) + { + // Find out if we want to try a match with this key, depending on + // 'when' and a '*' or '!' before the key. + switch (when) + { + case '*': try_match = (*look == '*'); break; + case '!': try_match = (*look == '!'); break; + default: try_match = (*look != '*'); break; + } + if (*look == '*' || *look == '!') + ++look; + + // If there is a '0', only accept a match if the line is empty. + // But may still match when typing last char of a word. + if (*look == '0') + { + try_match_word = try_match; + if (!line_is_empty) + try_match = FALSE; + ++look; + } + else + try_match_word = FALSE; + + // does it look like a control character? + if (*look == '^' && look[1] >= '?' && look[1] <= '_') + { + if (try_match && keytyped == Ctrl_chr(look[1])) + return TRUE; + look += 2; + } + // 'o' means "o" command, open forward. + // 'O' means "O" command, open backward. + else if (*look == 'o') + { + if (try_match && keytyped == KEY_OPEN_FORW) + return TRUE; + ++look; + } + else if (*look == 'O') + { + if (try_match && keytyped == KEY_OPEN_BACK) + return TRUE; + ++look; + } + + // 'e' means to check for "else" at start of line and just before the + // cursor. + else if (*look == 'e') + { + if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) + { + p = ml_get_curline(); + if (skipwhite(p) == p + curwin->w_cursor.col - 4 && + STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0) + return TRUE; + } + ++look; + } + + // ':' only causes an indent if it is at the end of a label or case + // statement, or when it was before typing the ':' (to fix + // class::method for C++). + else if (*look == ':') + { + if (try_match && keytyped == ':') + { + p = ml_get_curline(); + if (cin_iscase(p, FALSE) || cin_isscopedecl(p) || cin_islabel()) + return TRUE; + // Need to get the line again after cin_islabel(). + p = ml_get_curline(); + if (curwin->w_cursor.col > 2 + && p[curwin->w_cursor.col - 1] == ':' + && p[curwin->w_cursor.col - 2] == ':') + { + p[curwin->w_cursor.col - 1] = ' '; + i = (cin_iscase(p, FALSE) || cin_isscopedecl(p) + || cin_islabel()); + p = ml_get_curline(); + p[curwin->w_cursor.col - 1] = ':'; + if (i) + return TRUE; + } + } + ++look; + } + + + // Is it a key in <>, maybe? + else if (*look == '<') + { + if (try_match) + { + // make up some named keys , , , <0>, <>>, <<>, <*>, + // <:> and so that people can re-indent on o, O, e, 0, <, + // >, *, : and ! keys if they really really want to. + if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL + && keytyped == look[1]) + return TRUE; + + if (keytyped == get_special_key_code(look + 1)) + return TRUE; + } + while (*look && *look != '>') + look++; + while (*look == '>') + look++; + } + + // Is it a word: "=word"? + else if (*look == '=' && look[1] != ',' && look[1] != NUL) + { + ++look; + if (*look == '~') + { + icase = TRUE; + ++look; + } + else + icase = FALSE; + p = vim_strchr(look, ','); + if (p == NULL) + p = look + STRLEN(look); + if ((try_match || try_match_word) + && curwin->w_cursor.col >= (colnr_T)(p - look)) + { + int match = FALSE; + + if (keytyped == KEY_COMPLETE) + { + char_u *s; + + // Just completed a word, check if it starts with "look". + // search back for the start of a word. + line = ml_get_curline(); + if (has_mbyte) + { + char_u *n; + + for (s = line + curwin->w_cursor.col; s > line; s = n) + { + n = mb_prevptr(line, s); + if (!vim_iswordp(n)) + break; + } + } + else + for (s = line + curwin->w_cursor.col; s > line; --s) + if (!vim_iswordc(s[-1])) + break; + if (s + (p - look) <= line + curwin->w_cursor.col + && (icase + ? MB_STRNICMP(s, look, p - look) + : STRNCMP(s, look, p - look)) == 0) + match = TRUE; + } + else + // TODO: multi-byte + if (keytyped == (int)p[-1] || (icase && keytyped < 256 + && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1]))) + { + line = ml_get_cursor(); + if ((curwin->w_cursor.col == (colnr_T)(p - look) + || !vim_iswordc(line[-(p - look) - 1])) + && (icase + ? MB_STRNICMP(line - (p - look), look, p - look) + : STRNCMP(line - (p - look), look, p - look)) + == 0) + match = TRUE; + } + if (match && try_match_word && !try_match) + { + // "0=word": Check if there are only blanks before the + // word. + if (getwhitecols_curline() != + (int)(curwin->w_cursor.col - (p - look))) + match = FALSE; + } + if (match) + return TRUE; + } + look = p; + } + + // ok, it's a boring generic character. + else + { + if (try_match && *look == keytyped) + return TRUE; + if (*look != NUL) + ++look; + } + + // Skip over ", ". + look = skip_to_option_part(look); + } + return FALSE; +} + +/* + * Do C or expression indenting on the current line. + */ + void +do_c_expr_indent(void) +{ +#ifdef FEAT_EVAL + if (*curbuf->b_p_inde != NUL) + fixthisline(get_expr_indent); + else +#endif + fixthisline(get_c_indent); +} + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * "cindent(lnum)" function + */ + void +f_cindent(typval_T *argvars UNUSED, typval_T *rettv) +{ + pos_T pos; + linenr_T lnum; + + if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL) + return; + + pos = curwin->w_cursor; + lnum = tv_get_lnum(argvars); + if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) + { + curwin->w_cursor.lnum = lnum; + rettv->vval.v_number = get_c_indent(); + curwin->w_cursor = pos; + } + else + rettv->vval.v_number = -1; +} +#endif diff --git a/src/clientserver.c b/src/clientserver.c new file mode 100644 index 0000000..dfbb8a8 --- /dev/null +++ b/src/clientserver.c @@ -0,0 +1,1050 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * clientserver.c: functions for Client Server functionality + */ + +#include "vim.h" + +#if defined(FEAT_CLIENTSERVER) || defined(PROTO) + +static void cmdsrv_main(int *argc, char **argv, char_u *serverName_arg, char_u **serverStr); +static char_u *serverMakeName(char_u *arg, char *cmd); + +/* + * Replace termcodes such as and insert as key presses if there is room. + */ + void +server_to_input_buf(char_u *str) +{ + char_u *ptr = NULL; + char_u *cpo_save = p_cpo; + + // Set 'cpoptions' the way we want it. + // B set - backslashes are *not* treated specially + // k set - keycodes are *not* reverse-engineered + // < unset - sequences *are* interpreted + // The last but one parameter of replace_termcodes() is TRUE so that the + // sequence is recognised - needed for a real backslash. + p_cpo = (char_u *)"Bk"; + str = replace_termcodes(str, &ptr, REPTERM_DO_LT, NULL); + p_cpo = cpo_save; + + if (*ptr != NUL) // trailing CTRL-V results in nothing + { + /* + * Add the string to the input stream. + * Can't use add_to_input_buf() here, we now have K_SPECIAL bytes. + * + * First clear typed characters from the typeahead buffer, there could + * be half a mapping there. Then append to the existing string, so + * that multiple commands from a client are concatenated. + */ + if (typebuf.tb_maplen < typebuf.tb_len) + del_typebuf(typebuf.tb_len - typebuf.tb_maplen, typebuf.tb_maplen); + (void)ins_typebuf(str, REMAP_NONE, typebuf.tb_len, TRUE, FALSE); + + // Let input_available() know we inserted text in the typeahead + // buffer. + typebuf_was_filled = TRUE; + } + vim_free(ptr); +} + +/* + * Evaluate an expression that the client sent to a string. + */ + char_u * +eval_client_expr_to_string(char_u *expr) +{ + char_u *res; + int save_dbl = debug_break_level; + int save_ro = redir_off; + funccal_entry_T funccal_entry; + int did_save_funccal = FALSE; + +#if defined(FEAT_EVAL) + ch_log(NULL, "eval_client_expr_to_string(\"%s\")", expr); +#endif + + // Evaluate the expression at the toplevel, don't use variables local to + // the calling function. Except when in debug mode. + if (!debug_mode) + { + save_funccal(&funccal_entry); + did_save_funccal = TRUE; + } + + // Disable debugging, otherwise Vim hangs, waiting for "cont" to be + // typed. + debug_break_level = -1; + redir_off = 0; + // Do not display error message, otherwise Vim hangs, waiting for "cont" + // to be typed. Do generate errors so that try/catch works. + ++emsg_silent; + + res = eval_to_string(expr, TRUE, FALSE); + + debug_break_level = save_dbl; + redir_off = save_ro; + --emsg_silent; + if (emsg_silent < 0) + emsg_silent = 0; + if (did_save_funccal) + restore_funccal(); + + // A client can tell us to redraw, but not to display the cursor, so do + // that here. + setcursor(); + out_flush_cursor(FALSE, FALSE); + + return res; +} + +/* + * Evaluate a command or expression sent to ourselves. + */ + int +sendToLocalVim(char_u *cmd, int asExpr, char_u **result) +{ + if (asExpr) + { + char_u *ret; + + ret = eval_client_expr_to_string(cmd); + if (result != NULL) + { + if (ret == NULL) + { + char *err = _(e_invalid_expression_received); + size_t len = STRLEN(cmd) + STRLEN(err) + 5; + char_u *msg; + + msg = alloc(len); + if (msg != NULL) + vim_snprintf((char *)msg, len, "%s: \"%s\"", err, cmd); + *result = msg; + } + else + *result = ret; + } + else + vim_free(ret); + return ret == NULL ? -1 : 0; + } + server_to_input_buf(cmd); + return 0; +} + +/* + * If conversion is needed, convert "data" from "client_enc" to 'encoding' and + * return an allocated string. Otherwise return "data". + * "*tofree" is set to the result when it needs to be freed later. + */ + char_u * +serverConvert( + char_u *client_enc UNUSED, + char_u *data, + char_u **tofree) +{ + char_u *res = data; + + *tofree = NULL; + if (client_enc == NULL || p_enc == NULL) + return res; + + vimconv_T vimconv; + + vimconv.vc_type = CONV_NONE; + if (convert_setup(&vimconv, client_enc, p_enc) != FAIL + && vimconv.vc_type != CONV_NONE) + { + res = string_convert(&vimconv, data, NULL); + if (res == NULL) + res = data; + else + *tofree = res; + } + convert_setup(&vimconv, NULL, NULL); + return res; +} +#endif + +#if (defined(FEAT_CLIENTSERVER) && !defined(NO_VIM_MAIN)) || defined(PROTO) + +/* + * Common code for the X command server and the Win32 command server. + */ + +static char_u *build_drop_cmd(int filec, char **filev, int tabs, int sendReply); + +/* + * Do the client-server stuff, unless "--servername ''" was used. + */ + void +exec_on_server(mparm_T *parmp) +{ + if (parmp->serverName_arg != NULL && *parmp->serverName_arg == NUL) + return; + +# ifdef MSWIN + // Initialise the client/server messaging infrastructure. + serverInitMessaging(); +# endif + + /* + * When a command server argument was found, execute it. This may + * exit Vim when it was successful. Otherwise it's executed further + * on. Remember the encoding used here in "serverStrEnc". + */ + if (parmp->serverArg) + { + cmdsrv_main(&parmp->argc, parmp->argv, + parmp->serverName_arg, &parmp->serverStr); + parmp->serverStrEnc = vim_strsave(p_enc); + } + + // If we're still running, get the name to register ourselves. + // On Win32 can register right now, for X11 need to setup the + // clipboard first, it's further down. + parmp->servername = serverMakeName(parmp->serverName_arg, + parmp->argv[0]); +# ifdef MSWIN + if (parmp->servername != NULL) + { + serverSetName(parmp->servername); + vim_free(parmp->servername); + } +# endif +} + +/* + * Prepare for running as a Vim server. + */ + void +prepare_server(mparm_T *parmp) +{ +# if defined(FEAT_X11) + /* + * Register for remote command execution with :serversend and --remote + * unless there was a -X or a --servername '' on the command line. + * Only register nongui-vim's with an explicit --servername argument, + * or when compiling with autoservername. + * When running as root --servername is also required. + */ + if (X_DISPLAY != NULL && parmp->servername != NULL && ( +# if defined(FEAT_AUTOSERVERNAME) || defined(FEAT_GUI) + ( +# if defined(FEAT_AUTOSERVERNAME) + 1 +# else + gui.in_use +# endif +# ifdef UNIX + && getuid() != ROOT_UID +# endif + ) || +# endif + parmp->serverName_arg != NULL)) + { + (void)serverRegisterName(X_DISPLAY, parmp->servername); + vim_free(parmp->servername); + TIME_MSG("register server name"); + } + else + serverDelayedStartName = parmp->servername; +# endif + + /* + * Execute command ourselves if we're here because the send failed (or + * else we would have exited above). + */ + if (parmp->serverStr != NULL) + { + char_u *p; + + server_to_input_buf(serverConvert(parmp->serverStrEnc, + parmp->serverStr, &p)); + vim_free(p); + } +} + + static void +cmdsrv_main( + int *argc, + char **argv, + char_u *serverName_arg, + char_u **serverStr) +{ + char_u *res; + int i; + char_u *sname; + int ret; + int didone = FALSE; + int exiterr = 0; + char **newArgV = argv + 1; + int newArgC = 1, + Argc = *argc; + int argtype; +#define ARGTYPE_OTHER 0 +#define ARGTYPE_EDIT 1 +#define ARGTYPE_EDIT_WAIT 2 +#define ARGTYPE_SEND 3 + int silent = FALSE; + int tabs = FALSE; +# ifndef FEAT_X11 + HWND srv; +# else + Window srv; + + setup_term_clip(); +# endif + + sname = serverMakeName(serverName_arg, argv[0]); + if (sname == NULL) + return; + + /* + * Execute the command server related arguments and remove them + * from the argc/argv array; We may have to return into main() + */ + for (i = 1; i < Argc; i++) + { + res = NULL; + if (STRCMP(argv[i], "--") == 0) // end of option arguments + { + for (; i < *argc; i++) + { + *newArgV++ = argv[i]; + newArgC++; + } + break; + } + + if (STRICMP(argv[i], "--remote-send") == 0) + argtype = ARGTYPE_SEND; + else if (STRNICMP(argv[i], "--remote", 8) == 0) + { + char *p = argv[i] + 8; + + argtype = ARGTYPE_EDIT; + while (*p != NUL) + { + if (STRNICMP(p, "-wait", 5) == 0) + { + argtype = ARGTYPE_EDIT_WAIT; + p += 5; + } + else if (STRNICMP(p, "-silent", 7) == 0) + { + silent = TRUE; + p += 7; + } + else if (STRNICMP(p, "-tab", 4) == 0) + { + tabs = TRUE; + p += 4; + } + else + { + argtype = ARGTYPE_OTHER; + break; + } + } + } + else + argtype = ARGTYPE_OTHER; + + if (argtype != ARGTYPE_OTHER) + { + if (i == *argc - 1) + mainerr_arg_missing((char_u *)argv[i]); + if (argtype == ARGTYPE_SEND) + { + *serverStr = (char_u *)argv[i + 1]; + i++; + } + else + { + *serverStr = build_drop_cmd(*argc - i - 1, argv + i + 1, + tabs, argtype == ARGTYPE_EDIT_WAIT); + if (*serverStr == NULL) + { + // Probably out of memory, exit. + didone = TRUE; + exiterr = 1; + break; + } + Argc = i; + } +# ifdef FEAT_X11 + if (xterm_dpy == NULL) + { + mch_errmsg(_("No display")); + ret = -1; + } + else + ret = serverSendToVim(xterm_dpy, sname, *serverStr, + NULL, &srv, 0, 0, 0, silent); +# else + // Win32 always works? + ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, 0, silent); +# endif + if (ret < 0) + { + if (argtype == ARGTYPE_SEND) + { + // Failed to send, abort. + mch_errmsg(_(": Send failed.\n")); + didone = TRUE; + exiterr = 1; + } + else if (!silent) + // Let vim start normally. + mch_errmsg(_(": Send failed. Trying to execute locally\n")); + break; + } + +# ifdef FEAT_GUI_MSWIN + // Guess that when the server name starts with "g" it's a GUI + // server, which we can bring to the foreground here. + // Foreground() in the server doesn't work very well. + if (argtype != ARGTYPE_SEND && TOUPPER_ASC(*sname) == 'G') + SetForegroundWindow(srv); +# endif + + /* + * For --remote-wait: Wait until the server did edit each + * file. Also detect that the server no longer runs. + */ + if (argtype == ARGTYPE_EDIT_WAIT) + { + int numFiles = *argc - i - 1; + char_u *done = alloc(numFiles); +# ifdef FEAT_GUI_MSWIN + NOTIFYICONDATA ni; + int count = 0; + extern HWND message_window; +# endif + + if (numFiles > 0 && argv[i + 1][0] == '+') + // Skip "+cmd" argument, don't wait for it to be edited. + --numFiles; + +# ifdef FEAT_GUI_MSWIN + ni.cbSize = sizeof(ni); + ni.hWnd = message_window; + ni.uID = 0; + ni.uFlags = NIF_ICON|NIF_TIP; + ni.hIcon = LoadIcon((HINSTANCE)GetModuleHandle(0), "IDR_VIM"); + sprintf(ni.szTip, _("%d of %d edited"), count, numFiles); + Shell_NotifyIcon(NIM_ADD, &ni); +# endif + + // Wait for all files to unload in remote + vim_memset(done, 0, numFiles); + while (memchr(done, 0, numFiles) != NULL) + { + char_u *p; + int j; +# ifdef MSWIN + p = serverGetReply(srv, NULL, TRUE, TRUE, 0); + if (p == NULL) + break; +# else + if (serverReadReply(xterm_dpy, srv, &p, TRUE, -1) < 0) + break; +# endif + j = atoi((char *)p); + vim_free(p); + if (j >= 0 && j < numFiles) + { +# ifdef FEAT_GUI_MSWIN + ++count; + sprintf(ni.szTip, _("%d of %d edited"), + count, numFiles); + Shell_NotifyIcon(NIM_MODIFY, &ni); +# endif + done[j] = 1; + } + } +# ifdef FEAT_GUI_MSWIN + Shell_NotifyIcon(NIM_DELETE, &ni); +# endif + vim_free(done); + } + } + else if (STRICMP(argv[i], "--remote-expr") == 0) + { + if (i == *argc - 1) + mainerr_arg_missing((char_u *)argv[i]); +# ifdef MSWIN + // Win32 always works? + if (serverSendToVim(sname, (char_u *)argv[i + 1], + &res, NULL, 1, 0, FALSE) < 0) +# else + if (xterm_dpy == NULL) + mch_errmsg(_("No display: Send expression failed.\n")); + else if (serverSendToVim(xterm_dpy, sname, (char_u *)argv[i + 1], + &res, NULL, 1, 0, 1, FALSE) < 0) +# endif + { + if (res != NULL && *res != NUL) + { + // Output error from remote + mch_errmsg((char *)res); + VIM_CLEAR(res); + } + mch_errmsg(_(": Send expression failed.\n")); + } + } + else if (STRICMP(argv[i], "--serverlist") == 0) + { +# ifdef MSWIN + // Win32 always works? + res = serverGetVimNames(); +# else + if (xterm_dpy != NULL) + res = serverGetVimNames(xterm_dpy); +# endif + if (did_emsg) + mch_errmsg("\n"); + } + else if (STRICMP(argv[i], "--servername") == 0) + { + // Already processed. Take it out of the command line + i++; + continue; + } + else + { + *newArgV++ = argv[i]; + newArgC++; + continue; + } + didone = TRUE; + if (res != NULL && *res != NUL) + { + mch_msg((char *)res); + if (res[STRLEN(res) - 1] != '\n') + mch_msg("\n"); + } + vim_free(res); + } + + if (didone) + { + display_errors(); // display any collected messages + exit(exiterr); // Mission accomplished - get out + } + + // Return back into main() + *argc = newArgC; + vim_free(sname); +} + +/* + * Build a ":drop" command to send to a Vim server. + */ + static char_u * +build_drop_cmd( + int filec, + char **filev, + int tabs, // Use ":tab drop" instead of ":drop". + int sendReply) +{ + garray_T ga; + int i; + char_u *inicmd = NULL; + char_u *p; + char_u *cdp; + char_u *cwd; + + if (filec > 0 && filev[0][0] == '+') + { + inicmd = (char_u *)filev[0] + 1; + filev++; + filec--; + } + // Check if we have at least one argument. + if (filec <= 0) + mainerr_arg_missing((char_u *)filev[-1]); + + // Temporarily cd to the current directory to handle relative file names. + cwd = alloc(MAXPATHL); + if (cwd == NULL) + return NULL; + if (mch_dirname(cwd, MAXPATHL) != OK) + { + vim_free(cwd); + return NULL; + } + cdp = vim_strsave_escaped_ext(cwd, +#ifdef BACKSLASH_IN_FILENAME + (char_u *)"", // rem_backslash() will tell what chars to escape +#else + PATH_ESC_CHARS, +#endif + '\\', TRUE); + vim_free(cwd); + if (cdp == NULL) + return NULL; + ga_init2(&ga, 1, 100); + ga_concat(&ga, (char_u *)":cd "); + ga_concat(&ga, cdp); + + // Call inputsave() so that a prompt for an encryption key works. + ga_concat(&ga, (char_u *) + ":if exists('*inputsave')|call inputsave()|endif|"); + if (tabs) + ga_concat(&ga, (char_u *)"tab "); + ga_concat(&ga, (char_u *)"drop"); + for (i = 0; i < filec; i++) + { + // On Unix the shell has already expanded the wildcards, don't want to + // do it again in the Vim server. On MS-Windows only escape + // non-wildcard characters. + p = vim_strsave_escaped((char_u *)filev[i], +#ifdef UNIX + PATH_ESC_CHARS +#else + (char_u *)" \t%#" +#endif + ); + if (p == NULL) + { + vim_free(ga.ga_data); + return NULL; + } + ga_concat(&ga, (char_u *)" "); + ga_concat(&ga, p); + vim_free(p); + } + ga_concat(&ga, (char_u *) + "|if exists('*inputrestore')|call inputrestore()|endif"); + + // The :drop commands goes to Insert mode when 'insertmode' is set, use + // CTRL-\ CTRL-N again. + ga_concat(&ga, (char_u *)""); + + // Switch back to the correct current directory (prior to temporary path + // switch) unless 'autochdir' is set, in which case it will already be + // correct after the :drop command. With line breaks and spaces: + // if !exists('+acd') || !&acd + // if haslocaldir() + // cd - + // lcd - + // elseif getcwd() ==# 'current path' + // cd - + // endif + // endif + ga_concat(&ga, (char_u *)":if !exists('+acd')||!&acd|if haslocaldir()|"); + ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# '"); + ga_concat(&ga, cdp); + ga_concat(&ga, (char_u *)"'|cd -|endif|endif"); + vim_free(cdp); + + if (sendReply) + ga_concat(&ga, (char_u *)":call SetupRemoteReplies()"); + ga_concat(&ga, (char_u *)":"); + if (inicmd != NULL) + { + // Can't use after "inicmd", because a "startinsert" would cause + // the following commands to be inserted as text. Use a "|", + // hopefully "inicmd" does allow this... + ga_concat(&ga, inicmd); + ga_concat(&ga, (char_u *)"|"); + } + // Bring the window to the foreground, goto Insert mode when 'im' set and + // clear command line. + ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f"); + ga_append(&ga, NUL); + return ga.ga_data; +} + +/* + * Make our basic server name: use the specified "arg" if given, otherwise use + * the tail of the command "cmd" we were started with. + * Return the name in allocated memory. This doesn't include a serial number. + */ + static char_u * +serverMakeName(char_u *arg, char *cmd) +{ + char_u *p; + + if (arg != NULL && *arg != NUL) + p = vim_strsave_up(arg); + else + { + p = vim_strsave_up(gettail((char_u *)cmd)); + // Remove .exe or .bat from the name. + if (p != NULL && vim_strchr(p, '.') != NULL) + *vim_strchr(p, '.') = NUL; + } + return p; +} +#endif // FEAT_CLIENTSERVER + +#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) + static void +make_connection(void) +{ + if (X_DISPLAY == NULL +# ifdef FEAT_GUI + && !gui.in_use +# endif + ) + { + x_force_connect = TRUE; + setup_term_clip(); + x_force_connect = FALSE; + } +} + + static int +check_connection(void) +{ + make_connection(); + if (X_DISPLAY == NULL) + { + emsg(_(e_no_connection_to_x_server)); + return FAIL; + } + return OK; +} +#endif + +#ifdef FEAT_CLIENTSERVER + static void +remote_common(typval_T *argvars, typval_T *rettv, int expr) +{ + char_u *server_name; + char_u *keys; + char_u *r = NULL; + char_u buf[NUMBUFLEN]; + int timeout = 0; +# ifdef MSWIN + HWND w; +# else + Window w; +# endif + + if (check_restricted() || check_secure()) + return; + +# ifdef FEAT_X11 + if (check_connection() == FAIL) + return; +# endif + if (argvars[2].v_type != VAR_UNKNOWN + && argvars[3].v_type != VAR_UNKNOWN) + timeout = tv_get_number(&argvars[3]); + + server_name = tv_get_string_chk(&argvars[0]); + if (server_name == NULL) + return; // type error; errmsg already given + keys = tv_get_string_buf(&argvars[1], buf); +# ifdef MSWIN + if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0) +# else + if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout, + 0, TRUE) < 0) +# endif + { + if (r != NULL) + { + emsg((char *)r); // sending worked but evaluation failed + vim_free(r); + } + else + semsg(_(e_unable_to_send_to_str), server_name); + return; + } + + rettv->vval.v_string = r; + + if (argvars[2].v_type != VAR_UNKNOWN) + { + dictitem_T v; + char_u str[30]; + char_u *idvar; + + idvar = tv_get_string_chk(&argvars[2]); + if (idvar != NULL && *idvar != NUL) + { + sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w); + v.di_tv.v_type = VAR_STRING; + v.di_tv.vval.v_string = vim_strsave(str); + set_var(idvar, &v.di_tv, FALSE); + vim_free(v.di_tv.vval.v_string); + } + } +} +#endif + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * "remote_expr()" function + */ + void +f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + +#ifdef FEAT_CLIENTSERVER + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL + || check_for_opt_string_arg(argvars, 2) == FAIL + || (argvars[2].v_type != VAR_UNKNOWN + && check_for_opt_number_arg(argvars, 3) == FAIL))) + return; + + remote_common(argvars, rettv, TRUE); +#endif +} + +/* + * "remote_foreground()" function + */ + void +f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +#ifdef FEAT_CLIENTSERVER + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + +# ifdef MSWIN + // On Win32 it's done in this application. + { + char_u *server_name = tv_get_string_chk(&argvars[0]); + + if (server_name != NULL) + serverForeground(server_name); + } +# else + // Send a foreground() expression to the server. + argvars[1].v_type = VAR_STRING; + argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()"); + argvars[2].v_type = VAR_UNKNOWN; + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + remote_common(argvars, rettv, TRUE); + vim_free(argvars[1].vval.v_string); +# endif +#endif +} + + void +f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv) +{ +#ifdef FEAT_CLIENTSERVER + dictitem_T v; + char_u *s = NULL; +# ifdef MSWIN + long_u n = 0; +# endif + char_u *serverid; + + rettv->vval.v_number = -1; + if (check_restricted() || check_secure()) + return; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_opt_string_arg(argvars, 1) == FAIL)) + return; + + serverid = tv_get_string_chk(&argvars[0]); + if (serverid == NULL) + return; // type error; errmsg already given +# ifdef MSWIN + sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n); + if (n == 0) + rettv->vval.v_number = -1; + else + { + s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0); + rettv->vval.v_number = (s != NULL); + } +# else + if (check_connection() == FAIL) + return; + + rettv->vval.v_number = serverPeekReply(X_DISPLAY, + serverStrToWin(serverid), &s); +# endif + + if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0) + { + char_u *retvar; + + v.di_tv.v_type = VAR_STRING; + v.di_tv.vval.v_string = vim_strsave(s); + retvar = tv_get_string_chk(&argvars[1]); + if (retvar != NULL) + set_var(retvar, &v.di_tv, FALSE); + vim_free(v.di_tv.vval.v_string); + } +#else + rettv->vval.v_number = -1; +#endif +} + + void +f_remote_read(typval_T *argvars UNUSED, typval_T *rettv) +{ + char_u *r = NULL; + +#ifdef FEAT_CLIENTSERVER + char_u *serverid; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_opt_number_arg(argvars, 1) == FAIL)) + return; + + serverid = tv_get_string_chk(&argvars[0]); + if (serverid != NULL && !check_restricted() && !check_secure()) + { + int timeout = 0; +# ifdef MSWIN + // The server's HWND is encoded in the 'id' parameter + long_u n = 0; +# endif + + if (argvars[1].v_type != VAR_UNKNOWN) + timeout = tv_get_number(&argvars[1]); + +# ifdef MSWIN + sscanf((char *)serverid, SCANF_HEX_LONG_U, &n); + if (n != 0) + r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout); + if (r == NULL) +# else + if (check_connection() == FAIL + || serverReadReply(X_DISPLAY, serverStrToWin(serverid), + &r, FALSE, timeout) < 0) +# endif + emsg(_(e_unable_to_read_server_reply)); + } +#endif + rettv->v_type = VAR_STRING; + rettv->vval.v_string = r; +} + +/* + * "remote_send()" function + */ + void +f_remote_send(typval_T *argvars UNUSED, typval_T *rettv) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + +#ifdef FEAT_CLIENTSERVER + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL + || check_for_opt_string_arg(argvars, 2) == FAIL)) + return; + + remote_common(argvars, rettv, FALSE); +#endif +} + +/* + * "remote_startserver()" function + */ + void +f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +#ifdef FEAT_CLIENTSERVER + char_u *server; + + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + + server = tv_get_string_chk(&argvars[0]); + if (server == NULL) + return; // type error; errmsg already given + if (serverName != NULL) + emsg(_(e_already_started_server)); + else + { +# ifdef FEAT_X11 + if (check_connection() == OK) + serverRegisterName(X_DISPLAY, server); +# else + serverSetName(server); +# endif + } +#else + emsg(_(e_clientserver_feature_not_available)); +#endif +} + + void +f_server2client(typval_T *argvars UNUSED, typval_T *rettv) +{ +#ifdef FEAT_CLIENTSERVER + char_u buf[NUMBUFLEN]; + char_u *server; + char_u *reply; + + rettv->vval.v_number = -1; + if (check_restricted() || check_secure()) + return; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + server = tv_get_string_chk(&argvars[0]); + reply = tv_get_string_buf_chk(&argvars[1], buf); + if (server == NULL || reply == NULL) + return; + +# ifdef FEAT_X11 + if (check_connection() == FAIL) + return; +# endif + + if (serverSendReply(server, reply) < 0) + { + emsg(_(e_unable_to_send_to_client)); + return; + } + rettv->vval.v_number = 0; +#else + rettv->vval.v_number = -1; +#endif +} + + void +f_serverlist(typval_T *argvars UNUSED, typval_T *rettv) +{ + char_u *r = NULL; + +#ifdef FEAT_CLIENTSERVER +# ifdef MSWIN + r = serverGetVimNames(); +# else + make_connection(); + if (X_DISPLAY != NULL) + r = serverGetVimNames(X_DISPLAY); +# endif +#endif + rettv->v_type = VAR_STRING; + rettv->vval.v_string = r; +} +#endif diff --git a/src/clipboard.c b/src/clipboard.c new file mode 100644 index 0000000..4ce536a --- /dev/null +++ b/src/clipboard.c @@ -0,0 +1,2227 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * clipboard.c: Functions to handle the clipboard + */ + +#include "vim.h" + +#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD +# define WIN32_LEAN_AND_MEAN +# include +# include "winclip.pro" +#endif + +// Functions for copying and pasting text between applications. +// This is always included in a GUI version, but may also be included when the +// clipboard and mouse is available to a terminal version such as xterm. +// Note: there are some more functions in ops.c that handle selection stuff. +// +// Also note that the majority of functions here deal with the X 'primary' +// (visible - for Visual mode use) selection, and only that. There are no +// versions of these for the 'clipboard' selection, as Visual mode has no use +// for them. + +#if defined(FEAT_CLIPBOARD) || defined(PROTO) + +/* + * Selection stuff using Visual mode, for cutting and pasting text to other + * windows. + */ + +/* + * Call this to initialise the clipboard. Pass it FALSE if the clipboard code + * is included, but the clipboard can not be used, or TRUE if the clipboard can + * be used. Eg unix may call this with FALSE, then call it again with TRUE if + * the GUI starts. + */ + void +clip_init(int can_use) +{ + Clipboard_T *cb; + + cb = &clip_star; + for (;;) + { + cb->available = can_use; + cb->owned = FALSE; + cb->start.lnum = 0; + cb->start.col = 0; + cb->end.lnum = 0; + cb->end.col = 0; + cb->state = SELECT_CLEARED; + + if (cb == &clip_plus) + break; + cb = &clip_plus; + } +} + +/* + * Check whether the VIsual area has changed, and if so try to become the owner + * of the selection, and free any old converted selection we may still have + * lying around. If the VIsual mode has ended, make a copy of what was + * selected so we can still give it to others. Will probably have to make sure + * this is called whenever VIsual mode is ended. + */ + void +clip_update_selection(Clipboard_T *clip) +{ + pos_T start, end; + + // If visual mode is only due to a redo command ("."), then ignore it + if (!redo_VIsual_busy && VIsual_active && (State & MODE_NORMAL)) + { + if (LT_POS(VIsual, curwin->w_cursor)) + { + start = VIsual; + end = curwin->w_cursor; + if (has_mbyte) + end.col += (*mb_ptr2len)(ml_get_cursor()) - 1; + } + else + { + start = curwin->w_cursor; + end = VIsual; + } + if (!EQUAL_POS(clip->start, start) + || !EQUAL_POS(clip->end, end) + || clip->vmode != VIsual_mode) + { + clip_clear_selection(clip); + clip->start = start; + clip->end = end; + clip->vmode = VIsual_mode; + clip_free_selection(clip); + clip_own_selection(clip); + clip_gen_set_selection(clip); + } + } +} + + static int +clip_gen_own_selection(Clipboard_T *cbd) +{ +#ifdef FEAT_XCLIPBOARD +# ifdef FEAT_GUI + if (gui.in_use) + return clip_mch_own_selection(cbd); + else +# endif + return clip_xterm_own_selection(cbd); +#else + return clip_mch_own_selection(cbd); +#endif +} + + void +clip_own_selection(Clipboard_T *cbd) +{ + /* + * Also want to check somehow that we are reading from the keyboard rather + * than a mapping etc. + */ +#ifdef FEAT_X11 + // Always own the selection, we might have lost it without being + // notified, e.g. during a ":sh" command. + if (cbd->available) + { + int was_owned = cbd->owned; + + cbd->owned = (clip_gen_own_selection(cbd) == OK); + if (!was_owned && (cbd == &clip_star || cbd == &clip_plus)) + { + // May have to show a different kind of highlighting for the + // selected area. There is no specific redraw command for this, + // just redraw all windows on the current buffer. + if (cbd->owned + && (get_real_state() == MODE_VISUAL + || get_real_state() == MODE_SELECT) + && (cbd == &clip_star ? clip_isautosel_star() + : clip_isautosel_plus()) + && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC)) + redraw_curbuf_later(UPD_INVERTED_ALL); + } + } +#else + // Only own the clipboard when we didn't own it yet. + if (!cbd->owned && cbd->available) + cbd->owned = (clip_gen_own_selection(cbd) == OK); +#endif +} + + static void +clip_gen_lose_selection(Clipboard_T *cbd) +{ +#ifdef FEAT_XCLIPBOARD +# ifdef FEAT_GUI + if (gui.in_use) + clip_mch_lose_selection(cbd); + else +# endif + clip_xterm_lose_selection(cbd); +#else + clip_mch_lose_selection(cbd); +#endif +} + + void +clip_lose_selection(Clipboard_T *cbd) +{ +#ifdef FEAT_X11 + int was_owned = cbd->owned; +#endif + int visual_selection = FALSE; + + if (cbd == &clip_star || cbd == &clip_plus) + visual_selection = TRUE; + + clip_free_selection(cbd); + cbd->owned = FALSE; + if (visual_selection) + clip_clear_selection(cbd); + clip_gen_lose_selection(cbd); +#ifdef FEAT_X11 + if (visual_selection) + { + // May have to show a different kind of highlighting for the selected + // area. There is no specific redraw command for this, just redraw all + // windows on the current buffer. + if (was_owned + && (get_real_state() == MODE_VISUAL + || get_real_state() == MODE_SELECT) + && (cbd == &clip_star ? + clip_isautosel_star() : clip_isautosel_plus()) + && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC) + && !exiting) + { + update_curbuf(UPD_INVERTED_ALL); + setcursor(); + cursor_on(); + out_flush_cursor(TRUE, FALSE); + } + } +#endif +} + + static void +clip_copy_selection(Clipboard_T *clip) +{ + if (VIsual_active && (State & MODE_NORMAL) && clip->available) + { + clip_update_selection(clip); + clip_free_selection(clip); + clip_own_selection(clip); + if (clip->owned) + clip_get_selection(clip); + clip_gen_set_selection(clip); + } +} + +/* + * Save and restore clip_unnamed before doing possibly many changes. This + * prevents accessing the clipboard very often which might slow down Vim + * considerably. + */ +static int global_change_count = 0; // if set, inside a start_global_changes +static int clipboard_needs_update = FALSE; // clipboard needs to be updated +static int clip_did_set_selection = TRUE; + +/* + * Save clip_unnamed and reset it. + */ + void +start_global_changes(void) +{ + if (++global_change_count > 1) + return; + clip_unnamed_saved = clip_unnamed; + clipboard_needs_update = FALSE; + + if (clip_did_set_selection) + { + clip_unnamed = 0; + clip_did_set_selection = FALSE; + } +} + +/* + * Return TRUE if setting the clipboard was postponed, it already contains the + * right text. + */ + static int +is_clipboard_needs_update(void) +{ + return clipboard_needs_update; +} + +/* + * Restore clip_unnamed and set the selection when needed. + */ + void +end_global_changes(void) +{ + if (--global_change_count > 0) + // recursive + return; + if (!clip_did_set_selection) + { + clip_did_set_selection = TRUE; + clip_unnamed = clip_unnamed_saved; + clip_unnamed_saved = 0; + if (clipboard_needs_update) + { + // only store something in the clipboard, + // if we have yanked anything to it + if (clip_unnamed & CLIP_UNNAMED) + { + clip_own_selection(&clip_star); + clip_gen_set_selection(&clip_star); + } + if (clip_unnamed & CLIP_UNNAMED_PLUS) + { + clip_own_selection(&clip_plus); + clip_gen_set_selection(&clip_plus); + } + } + } + clipboard_needs_update = FALSE; +} + +/* + * Called when Visual mode is ended: update the selection. + */ + void +clip_auto_select(void) +{ + if (clip_isautosel_star()) + clip_copy_selection(&clip_star); + if (clip_isautosel_plus()) + clip_copy_selection(&clip_plus); +} + +/* + * Return TRUE if automatic selection of Visual area is desired for the * + * register. + */ + int +clip_isautosel_star(void) +{ + return ( +#ifdef FEAT_GUI + gui.in_use ? (vim_strchr(p_go, GO_ASEL) != NULL) : +#endif + clip_autoselect_star); +} + +/* + * Return TRUE if automatic selection of Visual area is desired for the + + * register. + */ + int +clip_isautosel_plus(void) +{ + return ( +#ifdef FEAT_GUI + gui.in_use ? (vim_strchr(p_go, GO_ASELPLUS) != NULL) : +#endif + clip_autoselect_plus); +} + + +/* + * Stuff for general mouse selection, without using Visual mode. + */ + +/* + * Compare two screen positions ala strcmp() + */ + static int +clip_compare_pos( + int row1, + int col1, + int row2, + int col2) +{ + if (row1 > row2) return(1); + if (row1 < row2) return(-1); + if (col1 > col2) return(1); + if (col1 < col2) return(-1); + return(0); +} + +// "how" flags for clip_invert_area() +#define CLIP_CLEAR 1 +#define CLIP_SET 2 +#define CLIP_TOGGLE 3 + +/* + * Invert or un-invert a rectangle of the screen. + * "invert" is true if the result is inverted. + */ + static void +clip_invert_rectangle( + Clipboard_T *cbd UNUSED, + int row_arg, + int col_arg, + int height_arg, + int width_arg, + int invert) +{ + int row = row_arg; + int col = col_arg; + int height = height_arg; + int width = width_arg; + +#ifdef FEAT_PROP_POPUP + // this goes on top of all popup windows + screen_zindex = CLIP_ZINDEX; + + if (col < cbd->min_col) + { + width -= cbd->min_col - col; + col = cbd->min_col; + } + if (width > cbd->max_col - col) + width = cbd->max_col - col; + if (row < cbd->min_row) + { + height -= cbd->min_row - row; + row = cbd->min_row; + } + if (height > cbd->max_row - row + 1) + height = cbd->max_row - row + 1; +#endif +#ifdef FEAT_GUI + if (gui.in_use) + gui_mch_invert_rectangle(row, col, height, width); + else +#endif + screen_draw_rectangle(row, col, height, width, invert); +#ifdef FEAT_PROP_POPUP + screen_zindex = 0; +#endif +} + +/* + * Invert a region of the display between a starting and ending row and column + * Values for "how": + * CLIP_CLEAR: undo inversion + * CLIP_SET: set inversion + * CLIP_TOGGLE: set inversion if pos1 < pos2, undo inversion otherwise. + * 0: invert (GUI only). + */ + static void +clip_invert_area( + Clipboard_T *cbd, + int row1, + int col1, + int row2, + int col2, + int how) +{ + int invert = FALSE; + int max_col; + +#ifdef FEAT_PROP_POPUP + max_col = cbd->max_col - 1; +#else + max_col = Columns - 1; +#endif + + if (how == CLIP_SET) + invert = TRUE; + + // Swap the from and to positions so the from is always before + if (clip_compare_pos(row1, col1, row2, col2) > 0) + { + int tmp_row, tmp_col; + + tmp_row = row1; + tmp_col = col1; + row1 = row2; + col1 = col2; + row2 = tmp_row; + col2 = tmp_col; + } + else if (how == CLIP_TOGGLE) + invert = TRUE; + + // If all on the same line, do it the easy way + if (row1 == row2) + { + clip_invert_rectangle(cbd, row1, col1, 1, col2 - col1, invert); + } + else + { + // Handle a piece of the first line + if (col1 > 0) + { + clip_invert_rectangle(cbd, row1, col1, 1, + (int)Columns - col1, invert); + row1++; + } + + // Handle a piece of the last line + if (col2 < max_col) + { + clip_invert_rectangle(cbd, row2, 0, 1, col2, invert); + row2--; + } + + // Handle the rectangle that's left + if (row2 >= row1) + clip_invert_rectangle(cbd, row1, 0, row2 - row1 + 1, + (int)Columns, invert); + } +} + +/* + * Start, continue or end a modeless selection. Used when editing the + * command-line, in the cmdline window and when the mouse is in a popup window. + */ + void +clip_modeless(int button, int is_click, int is_drag) +{ + int repeat; + + repeat = ((clip_star.mode == SELECT_MODE_CHAR + || clip_star.mode == SELECT_MODE_LINE) + && (mod_mask & MOD_MASK_2CLICK)) + || (clip_star.mode == SELECT_MODE_WORD + && (mod_mask & MOD_MASK_3CLICK)); + if (is_click && button == MOUSE_RIGHT) + { + // Right mouse button: If there was no selection, start one. + // Otherwise extend the existing selection. + if (clip_star.state == SELECT_CLEARED) + clip_start_selection(mouse_col, mouse_row, FALSE); + clip_process_selection(button, mouse_col, mouse_row, repeat); + } + else if (is_click) + clip_start_selection(mouse_col, mouse_row, repeat); + else if (is_drag) + { + // Don't try extending a selection if there isn't one. Happens when + // button-down is in the cmdline and them moving mouse upwards. + if (clip_star.state != SELECT_CLEARED) + clip_process_selection(button, mouse_col, mouse_row, repeat); + } + else // release + clip_process_selection(MOUSE_RELEASE, mouse_col, mouse_row, FALSE); +} + +/* + * Update the currently selected region by adding and/or subtracting from the + * beginning or end and inverting the changed area(s). + */ + static void +clip_update_modeless_selection( + Clipboard_T *cb, + int row1, + int col1, + int row2, + int col2) +{ + // See if we changed at the beginning of the selection + if (row1 != cb->start.lnum || col1 != (int)cb->start.col) + { + clip_invert_area(cb, row1, col1, (int)cb->start.lnum, cb->start.col, + CLIP_TOGGLE); + cb->start.lnum = row1; + cb->start.col = col1; + } + + // See if we changed at the end of the selection + if (row2 != cb->end.lnum || col2 != (int)cb->end.col) + { + clip_invert_area(cb, (int)cb->end.lnum, cb->end.col, row2, col2, + CLIP_TOGGLE); + cb->end.lnum = row2; + cb->end.col = col2; + } +} + +/* + * Find the starting and ending positions of the word at the given row and + * column. Only white-separated words are recognized here. + */ +#define CHAR_CLASS(c) (c <= ' ' ? ' ' : vim_iswordc(c)) + + static void +clip_get_word_boundaries(Clipboard_T *cb, int row, int col) +{ + int start_class; + int temp_col; + char_u *p; + int mboff; + + if (row >= screen_Rows || col >= screen_Columns || ScreenLines == NULL) + return; + + p = ScreenLines + LineOffset[row]; + // Correct for starting in the right half of a double-wide char + if (enc_dbcs != 0) + col -= dbcs_screen_head_off(p, p + col); + else if (enc_utf8 && p[col] == 0) + --col; + start_class = CHAR_CLASS(p[col]); + + temp_col = col; + for ( ; temp_col > 0; temp_col--) + if (enc_dbcs != 0 + && (mboff = dbcs_screen_head_off(p, p + temp_col - 1)) > 0) + temp_col -= mboff; + else if (CHAR_CLASS(p[temp_col - 1]) != start_class + && !(enc_utf8 && p[temp_col - 1] == 0)) + break; + cb->word_start_col = temp_col; + + temp_col = col; + for ( ; temp_col < screen_Columns; temp_col++) + if (enc_dbcs != 0 && dbcs_ptr2cells(p + temp_col) == 2) + ++temp_col; + else if (CHAR_CLASS(p[temp_col]) != start_class + && !(enc_utf8 && p[temp_col] == 0)) + break; + cb->word_end_col = temp_col; +} + +/* + * Find the column position for the last non-whitespace character on the given + * line at or before start_col. + */ + static int +clip_get_line_end(Clipboard_T *cbd UNUSED, int row) +{ + int i; + + if (row >= screen_Rows || ScreenLines == NULL) + return 0; + for (i = +#ifdef FEAT_PROP_POPUP + cbd->max_col; +#else + screen_Columns; +#endif + i > 0; i--) + if (ScreenLines[LineOffset[row] + i - 1] != ' ') + break; + return i; +} + +/* + * Start the selection + */ + void +clip_start_selection(int col, int row, int repeated_click) +{ + Clipboard_T *cb = &clip_star; +#ifdef FEAT_PROP_POPUP + win_T *wp; + int row_cp = row; + int col_cp = col; + + wp = mouse_find_win(&row_cp, &col_cp, FIND_POPUP); + if (wp != NULL && WIN_IS_POPUP(wp) + && popup_is_in_scrollbar(wp, row_cp, col_cp)) + // click or double click in scrollbar does not start a selection + return; +#endif + + if (cb->state == SELECT_DONE) + clip_clear_selection(cb); + + row = check_row(row); + col = check_col(col); + col = mb_fix_col(col, row); + + cb->start.lnum = row; + cb->start.col = col; + cb->end = cb->start; + cb->origin_row = (short_u)cb->start.lnum; + cb->state = SELECT_IN_PROGRESS; +#ifdef FEAT_PROP_POPUP + if (wp != NULL && WIN_IS_POPUP(wp)) + { + // Click in a popup window restricts selection to that window, + // excluding the border. + cb->min_col = wp->w_wincol + wp->w_popup_border[3]; + cb->max_col = wp->w_wincol + popup_width(wp) + - wp->w_popup_border[1] - wp->w_has_scrollbar; + if (cb->max_col > screen_Columns) + cb->max_col = screen_Columns; + cb->min_row = wp->w_winrow + wp->w_popup_border[0]; + cb->max_row = wp->w_winrow + popup_height(wp) - 1 + - wp->w_popup_border[2]; + } + else + { + cb->min_col = 0; + cb->max_col = screen_Columns; + cb->min_row = 0; + cb->max_row = screen_Rows; + } +#endif + + if (repeated_click) + { + if (++cb->mode > SELECT_MODE_LINE) + cb->mode = SELECT_MODE_CHAR; + } + else + cb->mode = SELECT_MODE_CHAR; + +#ifdef FEAT_GUI + // clear the cursor until the selection is made + if (gui.in_use) + gui_undraw_cursor(); +#endif + + switch (cb->mode) + { + case SELECT_MODE_CHAR: + cb->origin_start_col = cb->start.col; + cb->word_end_col = clip_get_line_end(cb, (int)cb->start.lnum); + break; + + case SELECT_MODE_WORD: + clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col); + cb->origin_start_col = cb->word_start_col; + cb->origin_end_col = cb->word_end_col; + + clip_invert_area(cb, (int)cb->start.lnum, cb->word_start_col, + (int)cb->end.lnum, cb->word_end_col, CLIP_SET); + cb->start.col = cb->word_start_col; + cb->end.col = cb->word_end_col; + break; + + case SELECT_MODE_LINE: + clip_invert_area(cb, (int)cb->start.lnum, 0, (int)cb->start.lnum, + (int)Columns, CLIP_SET); + cb->start.col = 0; + cb->end.col = Columns; + break; + } + + cb->prev = cb->start; + +#ifdef DEBUG_SELECTION + printf("Selection started at (%ld,%d)\n", cb->start.lnum, cb->start.col); +#endif +} + +/* + * Continue processing the selection + */ + void +clip_process_selection( + int button, + int col, + int row, + int_u repeated_click) +{ + Clipboard_T *cb = &clip_star; + int diff; + int slen = 1; // cursor shape width + + if (button == MOUSE_RELEASE) + { + if (cb->state != SELECT_IN_PROGRESS) + return; + + // Check to make sure we have something selected + if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col) + { +#ifdef FEAT_GUI + if (gui.in_use) + gui_update_cursor(FALSE, FALSE); +#endif + cb->state = SELECT_CLEARED; + return; + } + +#ifdef DEBUG_SELECTION + printf("Selection ended: (%ld,%d) to (%ld,%d)\n", cb->start.lnum, + cb->start.col, cb->end.lnum, cb->end.col); +#endif + if (clip_isautosel_star() + || ( +#ifdef FEAT_GUI + gui.in_use ? (vim_strchr(p_go, GO_ASELML) != NULL) : +#endif + clip_autoselectml)) + clip_copy_modeless_selection(FALSE); +#ifdef FEAT_GUI + if (gui.in_use) + gui_update_cursor(FALSE, FALSE); +#endif + + cb->state = SELECT_DONE; + return; + } + + row = check_row(row); + col = check_col(col); + col = mb_fix_col(col, row); + + if (col == (int)cb->prev.col && row == cb->prev.lnum && !repeated_click) + return; + + /* + * When extending the selection with the right mouse button, swap the + * start and end if the position is before half the selection + */ + if (cb->state == SELECT_DONE && button == MOUSE_RIGHT) + { + /* + * If the click is before the start, or the click is inside the + * selection and the start is the closest side, set the origin to the + * end of the selection. + */ + if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0 + || (clip_compare_pos(row, col, + (int)cb->end.lnum, cb->end.col) < 0 + && (((cb->start.lnum == cb->end.lnum + && cb->end.col - col > col - cb->start.col)) + || ((diff = (cb->end.lnum - row) - + (row - cb->start.lnum)) > 0 + || (diff == 0 && col < (int)(cb->start.col + + cb->end.col) / 2))))) + { + cb->origin_row = (short_u)cb->end.lnum; + cb->origin_start_col = cb->end.col - 1; + cb->origin_end_col = cb->end.col; + } + else + { + cb->origin_row = (short_u)cb->start.lnum; + cb->origin_start_col = cb->start.col; + cb->origin_end_col = cb->start.col; + } + if (cb->mode == SELECT_MODE_WORD && !repeated_click) + cb->mode = SELECT_MODE_CHAR; + } + + // set state, for when using the right mouse button + cb->state = SELECT_IN_PROGRESS; + +#ifdef DEBUG_SELECTION + printf("Selection extending to (%d,%d)\n", row, col); +#endif + + if (repeated_click && ++cb->mode > SELECT_MODE_LINE) + cb->mode = SELECT_MODE_CHAR; + + switch (cb->mode) + { + case SELECT_MODE_CHAR: + // If we're on a different line, find where the line ends + if (row != cb->prev.lnum) + cb->word_end_col = clip_get_line_end(cb, row); + + // See if we are before or after the origin of the selection + if (clip_compare_pos(row, col, cb->origin_row, + cb->origin_start_col) >= 0) + { + if (col >= (int)cb->word_end_col) + clip_update_modeless_selection(cb, cb->origin_row, + cb->origin_start_col, row, (int)Columns); + else + { + if (has_mbyte && mb_lefthalve(row, col)) + slen = 2; + clip_update_modeless_selection(cb, cb->origin_row, + cb->origin_start_col, row, col + slen); + } + } + else + { + if (has_mbyte + && mb_lefthalve(cb->origin_row, cb->origin_start_col)) + slen = 2; + if (col >= (int)cb->word_end_col) + clip_update_modeless_selection(cb, row, cb->word_end_col, + cb->origin_row, cb->origin_start_col + slen); + else + clip_update_modeless_selection(cb, row, col, + cb->origin_row, cb->origin_start_col + slen); + } + break; + + case SELECT_MODE_WORD: + // If we are still within the same word, do nothing + if (row == cb->prev.lnum && col >= (int)cb->word_start_col + && col < (int)cb->word_end_col && !repeated_click) + return; + + // Get new word boundaries + clip_get_word_boundaries(cb, row, col); + + // Handle being after the origin point of selection + if (clip_compare_pos(row, col, cb->origin_row, + cb->origin_start_col) >= 0) + clip_update_modeless_selection(cb, cb->origin_row, + cb->origin_start_col, row, cb->word_end_col); + else + clip_update_modeless_selection(cb, row, cb->word_start_col, + cb->origin_row, cb->origin_end_col); + break; + + case SELECT_MODE_LINE: + if (row == cb->prev.lnum && !repeated_click) + return; + + if (clip_compare_pos(row, col, cb->origin_row, + cb->origin_start_col) >= 0) + clip_update_modeless_selection(cb, cb->origin_row, 0, row, + (int)Columns); + else + clip_update_modeless_selection(cb, row, 0, cb->origin_row, + (int)Columns); + break; + } + + cb->prev.lnum = row; + cb->prev.col = col; + +#ifdef DEBUG_SELECTION + printf("Selection is: (%ld,%d) to (%ld,%d)\n", cb->start.lnum, + cb->start.col, cb->end.lnum, cb->end.col); +#endif +} + +# if defined(FEAT_GUI) || defined(PROTO) +/* + * Redraw part of the selection if character at "row,col" is inside of it. + * Only used for the GUI. + */ + void +clip_may_redraw_selection(int row, int col, int len) +{ + int start = col; + int end = col + len; + + if (clip_star.state != SELECT_CLEARED + && row >= clip_star.start.lnum + && row <= clip_star.end.lnum) + { + if (row == clip_star.start.lnum && start < (int)clip_star.start.col) + start = clip_star.start.col; + if (row == clip_star.end.lnum && end > (int)clip_star.end.col) + end = clip_star.end.col; + if (end > start) + clip_invert_area(&clip_star, row, start, row, end, 0); + } +} +# endif + +/* + * Called from outside to clear selected region from the display + */ + void +clip_clear_selection(Clipboard_T *cbd) +{ + + if (cbd->state == SELECT_CLEARED) + return; + + clip_invert_area(cbd, (int)cbd->start.lnum, cbd->start.col, + (int)cbd->end.lnum, cbd->end.col, CLIP_CLEAR); + cbd->state = SELECT_CLEARED; +} + +/* + * Clear the selection if any lines from "row1" to "row2" are inside of it. + */ + void +clip_may_clear_selection(int row1, int row2) +{ + if (clip_star.state == SELECT_DONE + && row2 >= clip_star.start.lnum + && row1 <= clip_star.end.lnum) + clip_clear_selection(&clip_star); +} + +/* + * Called before the screen is scrolled up or down. Adjusts the line numbers + * of the selection. Call with big number when clearing the screen. + */ + void +clip_scroll_selection( + int rows) // negative for scroll down +{ + int lnum; + + if (clip_star.state == SELECT_CLEARED) + return; + + lnum = clip_star.start.lnum - rows; + if (lnum <= 0) + clip_star.start.lnum = 0; + else if (lnum >= screen_Rows) // scrolled off of the screen + clip_star.state = SELECT_CLEARED; + else + clip_star.start.lnum = lnum; + + lnum = clip_star.end.lnum - rows; + if (lnum < 0) // scrolled off of the screen + clip_star.state = SELECT_CLEARED; + else if (lnum >= screen_Rows) + clip_star.end.lnum = screen_Rows - 1; + else + clip_star.end.lnum = lnum; +} + +/* + * Copy the currently selected area into the '*' register so it will be + * available for pasting. + * When "both" is TRUE also copy to the '+' register. + */ + void +clip_copy_modeless_selection(int both UNUSED) +{ + char_u *buffer; + char_u *bufp; + int row; + int start_col; + int end_col; + int line_end_col; + int add_newline_flag = FALSE; + int len; + char_u *p; + int row1 = clip_star.start.lnum; + int col1 = clip_star.start.col; + int row2 = clip_star.end.lnum; + int col2 = clip_star.end.col; + + // Can't use ScreenLines unless initialized + if (ScreenLines == NULL) + return; + + /* + * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2. + */ + if (row1 > row2) + { + row = row1; row1 = row2; row2 = row; + row = col1; col1 = col2; col2 = row; + } + else if (row1 == row2 && col1 > col2) + { + row = col1; col1 = col2; col2 = row; + } +#ifdef FEAT_PROP_POPUP + if (col1 < clip_star.min_col) + col1 = clip_star.min_col; + if (col2 > clip_star.max_col) + col2 = clip_star.max_col; + if (row1 > clip_star.max_row || row2 < clip_star.min_row) + return; + if (row1 < clip_star.min_row) + row1 = clip_star.min_row; + if (row2 > clip_star.max_row) + row2 = clip_star.max_row; +#endif + // correct starting point for being on right half of double-wide char + p = ScreenLines + LineOffset[row1]; + if (enc_dbcs != 0) + col1 -= (*mb_head_off)(p, p + col1); + else if (enc_utf8 && p[col1] == 0) + --col1; + + // Create a temporary buffer for storing the text + len = (row2 - row1 + 1) * Columns + 1; + if (enc_dbcs != 0) + len *= 2; // max. 2 bytes per display cell + else if (enc_utf8) + len *= MB_MAXBYTES; + buffer = alloc(len); + if (buffer == NULL) // out of memory + return; + + // Process each row in the selection + for (bufp = buffer, row = row1; row <= row2; row++) + { + if (row == row1) + start_col = col1; + else +#ifdef FEAT_PROP_POPUP + start_col = clip_star.min_col; +#else + start_col = 0; +#endif + + if (row == row2) + end_col = col2; + else +#ifdef FEAT_PROP_POPUP + end_col = clip_star.max_col; +#else + end_col = Columns; +#endif + + line_end_col = clip_get_line_end(&clip_star, row); + + // See if we need to nuke some trailing whitespace + if (end_col >= +#ifdef FEAT_PROP_POPUP + clip_star.max_col +#else + Columns +#endif + && (row < row2 || end_col > line_end_col)) + { + // Get rid of trailing whitespace + end_col = line_end_col; + if (end_col < start_col) + end_col = start_col; + + // If the last line extended to the end, add an extra newline + if (row == row2) + add_newline_flag = TRUE; + } + + // If after the first row, we need to always add a newline + if (row > row1 && !LineWraps[row - 1]) + *bufp++ = NL; + + // Safetey check for in case resizing went wrong + if (row < screen_Rows && end_col <= screen_Columns) + { + if (enc_dbcs != 0) + { + int i; + + p = ScreenLines + LineOffset[row]; + for (i = start_col; i < end_col; ++i) + if (enc_dbcs == DBCS_JPNU && p[i] == 0x8e) + { + // single-width double-byte char + *bufp++ = 0x8e; + *bufp++ = ScreenLines2[LineOffset[row] + i]; + } + else + { + *bufp++ = p[i]; + if (MB_BYTE2LEN(p[i]) == 2) + *bufp++ = p[++i]; + } + } + else if (enc_utf8) + { + int off; + int i; + int ci; + + off = LineOffset[row]; + for (i = start_col; i < end_col; ++i) + { + // The base character is either in ScreenLinesUC[] or + // ScreenLines[]. + if (ScreenLinesUC[off + i] == 0) + *bufp++ = ScreenLines[off + i]; + else + { + bufp += utf_char2bytes(ScreenLinesUC[off + i], bufp); + for (ci = 0; ci < Screen_mco; ++ci) + { + // Add a composing character. + if (ScreenLinesC[ci][off + i] == 0) + break; + bufp += utf_char2bytes(ScreenLinesC[ci][off + i], + bufp); + } + } + // Skip right half of double-wide character. + if (ScreenLines[off + i + 1] == 0) + ++i; + } + } + else + { + STRNCPY(bufp, ScreenLines + LineOffset[row] + start_col, + end_col - start_col); + bufp += end_col - start_col; + } + } + } + + // Add a newline at the end if the selection ended there + if (add_newline_flag) + *bufp++ = NL; + + // First cleanup any old selection and become the owner. + clip_free_selection(&clip_star); + clip_own_selection(&clip_star); + + // Yank the text into the '*' register. + clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_star); + + // Make the register contents available to the outside world. + clip_gen_set_selection(&clip_star); + +#ifdef FEAT_X11 + if (both) + { + // Do the same for the '+' register. + clip_free_selection(&clip_plus); + clip_own_selection(&clip_plus); + clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_plus); + clip_gen_set_selection(&clip_plus); + } +#endif + vim_free(buffer); +} + + void +clip_gen_set_selection(Clipboard_T *cbd) +{ + if (!clip_did_set_selection) + { + // Updating postponed, so that accessing the system clipboard won't + // hang Vim when accessing it many times (e.g. on a :g command). + if ((cbd == &clip_plus && (clip_unnamed_saved & CLIP_UNNAMED_PLUS)) + || (cbd == &clip_star && (clip_unnamed_saved & CLIP_UNNAMED))) + { + clipboard_needs_update = TRUE; + return; + } + } +#ifdef FEAT_XCLIPBOARD +# ifdef FEAT_GUI + if (gui.in_use) + clip_mch_set_selection(cbd); + else +# endif + clip_xterm_set_selection(cbd); +#else + clip_mch_set_selection(cbd); +#endif +} + + static void +clip_gen_request_selection(Clipboard_T *cbd) +{ +#ifdef FEAT_XCLIPBOARD +# ifdef FEAT_GUI + if (gui.in_use) + clip_mch_request_selection(cbd); + else +# endif + clip_xterm_request_selection(cbd); +#else + clip_mch_request_selection(cbd); +#endif +} + +#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD) && defined(USE_SYSTEM)) \ + || defined(PROTO) + static int +clip_x11_owner_exists(Clipboard_T *cbd) +{ + return XGetSelectionOwner(X_DISPLAY, cbd->sel_atom) != None; +} +#endif + +#if (defined(FEAT_X11) && defined(USE_SYSTEM)) || defined(PROTO) + int +clip_gen_owner_exists(Clipboard_T *cbd UNUSED) +{ +#ifdef FEAT_XCLIPBOARD +# ifdef FEAT_GUI_GTK + if (gui.in_use) + return clip_gtk_owner_exists(cbd); + else +# endif + return clip_x11_owner_exists(cbd); +#else + return TRUE; +#endif +} +#endif + +/* + * Extract the items in the 'clipboard' option and set global values. + * Return an error message or NULL for success. + */ + char * +did_set_clipboard(optset_T *args UNUSED) +{ + int new_unnamed = 0; + int new_autoselect_star = FALSE; + int new_autoselect_plus = FALSE; + int new_autoselectml = FALSE; + int new_html = FALSE; + regprog_T *new_exclude_prog = NULL; + char *errmsg = NULL; + char_u *p; + + for (p = p_cb; *p != NUL; ) + { + if (STRNCMP(p, "unnamed", 7) == 0 && (p[7] == ',' || p[7] == NUL)) + { + new_unnamed |= CLIP_UNNAMED; + p += 7; + } + else if (STRNCMP(p, "unnamedplus", 11) == 0 + && (p[11] == ',' || p[11] == NUL)) + { + new_unnamed |= CLIP_UNNAMED_PLUS; + p += 11; + } + else if (STRNCMP(p, "autoselect", 10) == 0 + && (p[10] == ',' || p[10] == NUL)) + { + new_autoselect_star = TRUE; + p += 10; + } + else if (STRNCMP(p, "autoselectplus", 14) == 0 + && (p[14] == ',' || p[14] == NUL)) + { + new_autoselect_plus = TRUE; + p += 14; + } + else if (STRNCMP(p, "autoselectml", 12) == 0 + && (p[12] == ',' || p[12] == NUL)) + { + new_autoselectml = TRUE; + p += 12; + } + else if (STRNCMP(p, "html", 4) == 0 && (p[4] == ',' || p[4] == NUL)) + { + new_html = TRUE; + p += 4; + } + else if (STRNCMP(p, "exclude:", 8) == 0 && new_exclude_prog == NULL) + { + p += 8; + new_exclude_prog = vim_regcomp(p, RE_MAGIC); + if (new_exclude_prog == NULL) + errmsg = e_invalid_argument; + break; + } + else + { + errmsg = e_invalid_argument; + break; + } + if (*p == ',') + ++p; + } + if (errmsg == NULL) + { + if (global_busy) + // clip_unnamed will be reset to clip_unnamed_saved + // at end_global_changes + clip_unnamed_saved = new_unnamed; + else + clip_unnamed = new_unnamed; + clip_autoselect_star = new_autoselect_star; + clip_autoselect_plus = new_autoselect_plus; + clip_autoselectml = new_autoselectml; + clip_html = new_html; + vim_regfree(clip_exclude_prog); + clip_exclude_prog = new_exclude_prog; +#ifdef FEAT_GUI_GTK + if (gui.in_use) + { + gui_gtk_set_selection_targets(); + gui_gtk_set_dnd_targets(); + } +#endif + } + else + vim_regfree(new_exclude_prog); + + return errmsg; +} + +/* + * Stuff for the X clipboard. Shared between VMS and Unix. + */ + +#if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) || defined(PROTO) +# include +# include + +/* + * Open the application context (if it hasn't been opened yet). + * Used for Motif GUI and the xterm clipboard. + */ + void +open_app_context(void) +{ + if (app_context == NULL) + { + XtToolkitInitialize(); + app_context = XtCreateApplicationContext(); + } +} + +static Atom vim_atom; // Vim's own special selection format +static Atom vimenc_atom; // Vim's extended selection format +static Atom utf8_atom; +static Atom compound_text_atom; +static Atom text_atom; +static Atom targets_atom; +static Atom timestamp_atom; // Used to get a timestamp + + void +x11_setup_atoms(Display *dpy) +{ + vim_atom = XInternAtom(dpy, VIM_ATOM_NAME, False); + vimenc_atom = XInternAtom(dpy, VIMENC_ATOM_NAME,False); + utf8_atom = XInternAtom(dpy, "UTF8_STRING", False); + compound_text_atom = XInternAtom(dpy, "COMPOUND_TEXT", False); + text_atom = XInternAtom(dpy, "TEXT", False); + targets_atom = XInternAtom(dpy, "TARGETS", False); + clip_star.sel_atom = XA_PRIMARY; + clip_plus.sel_atom = XInternAtom(dpy, "CLIPBOARD", False); + timestamp_atom = XInternAtom(dpy, "TIMESTAMP", False); +} + +/* + * X Selection stuff, for cutting and pasting text to other windows. + */ + + static Boolean +clip_x11_convert_selection_cb( + Widget w UNUSED, + Atom *sel_atom, + Atom *target, + Atom *type, + XtPointer *value, + long_u *length, + int *format) +{ + static char_u *save_result = NULL; + static long_u save_length = 0; + char_u *string; + int motion_type; + Clipboard_T *cbd; + int i; + + if (*sel_atom == clip_plus.sel_atom) + cbd = &clip_plus; + else + cbd = &clip_star; + + if (!cbd->owned) + return False; // Shouldn't ever happen + + // requestor wants to know what target types we support + if (*target == targets_atom) + { + static Atom array[7]; + + *value = (XtPointer)array; + i = 0; + array[i++] = targets_atom; + array[i++] = vimenc_atom; + array[i++] = vim_atom; + if (enc_utf8) + array[i++] = utf8_atom; + array[i++] = XA_STRING; + array[i++] = text_atom; + array[i++] = compound_text_atom; + + *type = XA_ATOM; + // This used to be: *format = sizeof(Atom) * 8; but that caused + // crashes on 64 bit machines. (Peter Derr) + *format = 32; + *length = i; + return True; + } + + if ( *target != XA_STRING + && *target != vimenc_atom + && (*target != utf8_atom || !enc_utf8) + && *target != vim_atom + && *target != text_atom + && *target != compound_text_atom) + return False; + + clip_get_selection(cbd); + motion_type = clip_convert_selection(&string, length, cbd); + if (motion_type < 0) + return False; + + // For our own format, the first byte contains the motion type + if (*target == vim_atom) + (*length)++; + + // Our own format with encoding: motion 'encoding' NUL text + if (*target == vimenc_atom) + *length += STRLEN(p_enc) + 2; + + if (save_length < *length || save_length / 2 >= *length) + *value = XtRealloc((char *)save_result, (Cardinal)*length + 1); + else + *value = save_result; + if (*value == NULL) + { + vim_free(string); + return False; + } + save_result = (char_u *)*value; + save_length = *length; + + if (*target == XA_STRING || (*target == utf8_atom && enc_utf8)) + { + mch_memmove(save_result, string, (size_t)(*length)); + *type = *target; + } + else if (*target == compound_text_atom || *target == text_atom) + { + XTextProperty text_prop; + char *string_nt = (char *)save_result; + int conv_result; + + // create NUL terminated string which XmbTextListToTextProperty wants + mch_memmove(string_nt, string, (size_t)*length); + string_nt[*length] = NUL; + conv_result = XmbTextListToTextProperty(X_DISPLAY, &string_nt, + 1, XCompoundTextStyle, &text_prop); + if (conv_result != Success) + { + vim_free(string); + return False; + } + *value = (XtPointer)(text_prop.value); // from plain text + *length = text_prop.nitems; + *type = compound_text_atom; + XtFree((char *)save_result); + save_result = (char_u *)*value; + save_length = *length; + } + else if (*target == vimenc_atom) + { + int l = STRLEN(p_enc); + + save_result[0] = motion_type; + STRCPY(save_result + 1, p_enc); + mch_memmove(save_result + l + 2, string, (size_t)(*length - l - 2)); + *type = vimenc_atom; + } + else + { + save_result[0] = motion_type; + mch_memmove(save_result + 1, string, (size_t)(*length - 1)); + *type = vim_atom; + } + *format = 8; // 8 bits per char + vim_free(string); + return True; +} + + static void +clip_x11_lose_ownership_cb(Widget w UNUSED, Atom *sel_atom) +{ + if (*sel_atom == clip_plus.sel_atom) + clip_lose_selection(&clip_plus); + else + clip_lose_selection(&clip_star); +} + + static void +clip_x11_notify_cb(Widget w UNUSED, Atom *sel_atom UNUSED, Atom *target UNUSED) +{ + // To prevent automatically freeing the selection value. +} + +/* + * Property callback to get a timestamp for XtOwnSelection. + */ +# if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO) + static void +clip_x11_timestamp_cb( + Widget w, + XtPointer n UNUSED, + XEvent *event, + Boolean *cont UNUSED) +{ + Atom actual_type; + int format; + unsigned long nitems, bytes_after; + unsigned char *prop=NULL; + XPropertyEvent *xproperty=&event->xproperty; + + // Must be a property notify, state can't be Delete (True), has to be + // one of the supported selection types. + if (event->type != PropertyNotify || xproperty->state + || (xproperty->atom != clip_star.sel_atom + && xproperty->atom != clip_plus.sel_atom)) + return; + + if (XGetWindowProperty(xproperty->display, xproperty->window, + xproperty->atom, 0, 0, False, timestamp_atom, &actual_type, &format, + &nitems, &bytes_after, &prop)) + return; + + if (prop) + XFree(prop); + + // Make sure the property type is "TIMESTAMP" and it's 32 bits. + if (actual_type != timestamp_atom || format != 32) + return; + + // Get the selection, using the event timestamp. + if (XtOwnSelection(w, xproperty->atom, xproperty->time, + clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb, + clip_x11_notify_cb) == OK) + { + // Set the "owned" flag now, there may have been a call to + // lose_ownership_cb in between. + if (xproperty->atom == clip_plus.sel_atom) + clip_plus.owned = TRUE; + else + clip_star.owned = TRUE; + } +} + + void +x11_setup_selection(Widget w) +{ + XtAddEventHandler(w, PropertyChangeMask, False, + /*(XtEventHandler)*/clip_x11_timestamp_cb, (XtPointer)NULL); +} +# endif + + static void +clip_x11_request_selection_cb( + Widget w UNUSED, + XtPointer success, + Atom *sel_atom, + Atom *type, + XtPointer value, + long_u *length, + int *format) +{ + int motion_type = MAUTO; + long_u len; + char_u *p; + char **text_list = NULL; + Clipboard_T *cbd; + char_u *tmpbuf = NULL; + + if (*sel_atom == clip_plus.sel_atom) + cbd = &clip_plus; + else + cbd = &clip_star; + + if (value == NULL || *length == 0) + { + clip_free_selection(cbd); // nothing received, clear register + *(int *)success = FALSE; + return; + } + p = (char_u *)value; + len = *length; + if (*type == vim_atom) + { + motion_type = *p++; + len--; + } + + else if (*type == vimenc_atom) + { + char_u *enc; + vimconv_T conv; + int convlen; + + motion_type = *p++; + --len; + + enc = p; + p += STRLEN(p) + 1; + len -= p - enc; + + // If the encoding of the text is different from 'encoding', attempt + // converting it. + conv.vc_type = CONV_NONE; + convert_setup(&conv, enc, p_enc); + if (conv.vc_type != CONV_NONE) + { + convlen = len; // Need to use an int here. + tmpbuf = string_convert(&conv, p, &convlen); + len = convlen; + if (tmpbuf != NULL) + p = tmpbuf; + convert_setup(&conv, NULL, NULL); + } + } + + else if (*type == compound_text_atom + || *type == utf8_atom + || (enc_dbcs != 0 && *type == text_atom)) + { + XTextProperty text_prop; + int n_text = 0; + int status; + + text_prop.value = (unsigned char *)value; + text_prop.encoding = *type; + text_prop.format = *format; + text_prop.nitems = len; +#if defined(X_HAVE_UTF8_STRING) + if (*type == utf8_atom) + status = Xutf8TextPropertyToTextList(X_DISPLAY, &text_prop, + &text_list, &n_text); + else +#endif + status = XmbTextPropertyToTextList(X_DISPLAY, &text_prop, + &text_list, &n_text); + if (status != Success || n_text < 1) + { + *(int *)success = FALSE; + return; + } + p = (char_u *)text_list[0]; + len = STRLEN(p); + } + clip_yank_selection(motion_type, p, (long)len, cbd); + + if (text_list != NULL) + XFreeStringList(text_list); + vim_free(tmpbuf); + XtFree((char *)value); + *(int *)success = TRUE; +} + + void +clip_x11_request_selection( + Widget myShell, + Display *dpy, + Clipboard_T *cbd) +{ + XEvent event; + Atom type; + static int success; + int i; + time_t start_time; + int timed_out = FALSE; + + for (i = 0; i < 6; i++) + { + switch (i) + { + case 0: type = vimenc_atom; break; + case 1: type = vim_atom; break; + case 2: type = utf8_atom; break; + case 3: type = compound_text_atom; break; + case 4: type = text_atom; break; + default: type = XA_STRING; + } + if (type == utf8_atom +# if defined(X_HAVE_UTF8_STRING) + && !enc_utf8 +# endif + ) + // Only request utf-8 when 'encoding' is utf8 and + // Xutf8TextPropertyToTextList is available. + continue; + success = MAYBE; + XtGetSelectionValue(myShell, cbd->sel_atom, type, + clip_x11_request_selection_cb, (XtPointer)&success, CurrentTime); + + // Make sure the request for the selection goes out before waiting for + // a response. + XFlush(dpy); + + /* + * Wait for result of selection request, otherwise if we type more + * characters, then they will appear before the one that requested the + * paste! Don't worry, we will catch up with any other events later. + */ + start_time = time(NULL); + while (success == MAYBE) + { + if (XCheckTypedEvent(dpy, PropertyNotify, &event) + || XCheckTypedEvent(dpy, SelectionNotify, &event) + || XCheckTypedEvent(dpy, SelectionRequest, &event)) + { + // This is where clip_x11_request_selection_cb() should be + // called. It may actually happen a bit later, so we loop + // until "success" changes. + // We may get a SelectionRequest here and if we don't handle + // it we hang. KDE klipper does this, for example. + // We need to handle a PropertyNotify for large selections. + XtDispatchEvent(&event); + continue; + } + + // Time out after 2 to 3 seconds to avoid that we hang when the + // other process doesn't respond. Note that the SelectionNotify + // event may still come later when the selection owner comes back + // to life and the text gets inserted unexpectedly. Don't know + // why that happens or how to avoid that :-(. + if (time(NULL) > start_time + 2) + { + timed_out = TRUE; + break; + } + + // Do we need this? Probably not. + XSync(dpy, False); + + // Wait for 1 msec to avoid that we eat up all CPU time. + ui_delay(1L, TRUE); + } + + if (success == TRUE) + return; + + // don't do a retry with another type after timing out, otherwise we + // hang for 15 seconds. + if (timed_out) + break; + } + + // Final fallback position - use the X CUT_BUFFER0 store + yank_cut_buffer0(dpy, cbd); +} + + void +clip_x11_lose_selection(Widget myShell, Clipboard_T *cbd) +{ + XtDisownSelection(myShell, cbd->sel_atom, + XtLastTimestampProcessed(XtDisplay(myShell))); +} + + int +clip_x11_own_selection(Widget myShell, Clipboard_T *cbd) +{ + // When using the GUI we have proper timestamps, use the one of the last + // event. When in the console we don't get events (the terminal gets + // them), Get the time by a zero-length append, clip_x11_timestamp_cb will + // be called with the current timestamp. +#ifdef FEAT_GUI + if (gui.in_use) + { + if (XtOwnSelection(myShell, cbd->sel_atom, + XtLastTimestampProcessed(XtDisplay(myShell)), + clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb, + clip_x11_notify_cb) == False) + return FAIL; + } + else +#endif + { + if (!XChangeProperty(XtDisplay(myShell), XtWindow(myShell), + cbd->sel_atom, timestamp_atom, 32, PropModeAppend, NULL, 0)) + return FAIL; + } + // Flush is required in a terminal as nothing else is doing it. + XFlush(XtDisplay(myShell)); + return OK; +} + +/* + * Send the current selection to the clipboard. Do nothing for X because we + * will fill in the selection only when requested by another app. + */ + void +clip_x11_set_selection(Clipboard_T *cbd UNUSED) +{ +} + +#endif + +#if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) \ + || defined(FEAT_GUI_GTK) || defined(PROTO) +/* + * Get the contents of the X CUT_BUFFER0 and put it in "cbd". + */ + void +yank_cut_buffer0(Display *dpy, Clipboard_T *cbd) +{ + int nbytes = 0; + char_u *buffer = (char_u *)XFetchBuffer(dpy, &nbytes, 0); + + if (nbytes > 0) + { + int done = FALSE; + + // CUT_BUFFER0 is supposed to be always latin1. Convert to 'enc' when + // using a multi-byte encoding. Conversion between two 8-bit + // character sets usually fails and the text might actually be in + // 'enc' anyway. + if (has_mbyte) + { + char_u *conv_buf; + vimconv_T vc; + + vc.vc_type = CONV_NONE; + if (convert_setup(&vc, (char_u *)"latin1", p_enc) == OK) + { + conv_buf = string_convert(&vc, buffer, &nbytes); + if (conv_buf != NULL) + { + clip_yank_selection(MCHAR, conv_buf, (long)nbytes, cbd); + vim_free(conv_buf); + done = TRUE; + } + convert_setup(&vc, NULL, NULL); + } + } + if (!done) // use the text without conversion + clip_yank_selection(MCHAR, buffer, (long)nbytes, cbd); + XFree((void *)buffer); + if (p_verbose > 0) + { + verbose_enter(); + verb_msg(_("Used CUT_BUFFER0 instead of empty selection")); + verbose_leave(); + } + } +} +#endif + +/* + * SELECTION / PRIMARY ('*') + * + * Text selection stuff that uses the GUI selection register '*'. When using a + * GUI this may be text from another window, otherwise it is the last text we + * had highlighted with VIsual mode. With mouse support, clicking the middle + * button performs the paste, otherwise you will need to do <"*p>. " + * If not under X, it is synonymous with the clipboard register '+'. + * + * X CLIPBOARD ('+') + * + * Text selection stuff that uses the GUI clipboard register '+'. + * Under X, this matches the standard cut/paste buffer CLIPBOARD selection. + * It will be used for unnamed cut/pasting is 'clipboard' contains "unnamed", + * otherwise you will need to do <"+p>. " + * If not under X, it is synonymous with the selection register '*'. + */ + +/* + * Routine to export any final X selection we had to the environment + * so that the text is still available after Vim has exited. X selections + * only exist while the owning application exists, so we write to the + * permanent (while X runs) store CUT_BUFFER0. + * Dump the CLIPBOARD selection if we own it (it's logically the more + * 'permanent' of the two), otherwise the PRIMARY one. + * For now, use a hard-coded sanity limit of 1Mb of data. + */ +#if (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO) + void +x11_export_final_selection(void) +{ + Display *dpy; + char_u *str = NULL; + long_u len = 0; + int motion_type = -1; + +# ifdef FEAT_GUI + if (gui.in_use) + dpy = X_DISPLAY; + else +# endif +# ifdef FEAT_XCLIPBOARD + dpy = xterm_dpy; +# else + return; +# endif + + // Get selection to export + if (clip_plus.owned) + motion_type = clip_convert_selection(&str, &len, &clip_plus); + else if (clip_star.owned) + motion_type = clip_convert_selection(&str, &len, &clip_star); + + // Check it's OK + if (dpy != NULL && str != NULL && motion_type >= 0 + && len < 1024*1024 && len > 0) + { + int ok = TRUE; + + // The CUT_BUFFER0 is supposed to always contain latin1. Convert from + // 'enc' when it is a multi-byte encoding. When 'enc' is an 8-bit + // encoding conversion usually doesn't work, so keep the text as-is. + if (has_mbyte) + { + vimconv_T vc; + + vc.vc_type = CONV_NONE; + if (convert_setup(&vc, p_enc, (char_u *)"latin1") == OK) + { + int intlen = len; + char_u *conv_str; + + vc.vc_fail = TRUE; + conv_str = string_convert(&vc, str, &intlen); + len = intlen; + if (conv_str != NULL) + { + vim_free(str); + str = conv_str; + } + else + { + ok = FALSE; + } + convert_setup(&vc, NULL, NULL); + } + else + { + ok = FALSE; + } + } + + // Do not store the string if conversion failed. Better to use any + // other selection than garbled text. + if (ok) + { + XStoreBuffer(dpy, (char *)str, (int)len, 0); + XFlush(dpy); + } + } + + vim_free(str); +} +#endif + + void +clip_free_selection(Clipboard_T *cbd) +{ + yankreg_T *y_ptr = get_y_current(); + + if (cbd == &clip_plus) + set_y_current(get_y_register(PLUS_REGISTER)); + else + set_y_current(get_y_register(STAR_REGISTER)); + free_yank_all(); + get_y_current()->y_size = 0; + set_y_current(y_ptr); +} + +/* + * Get the selected text and put it in register '*' or '+'. + */ + void +clip_get_selection(Clipboard_T *cbd) +{ + yankreg_T *old_y_previous, *old_y_current; + pos_T old_cursor; + pos_T old_visual; + int old_visual_mode; + colnr_T old_curswant; + int old_set_curswant; + pos_T old_op_start, old_op_end; + oparg_T oa; + cmdarg_T ca; + + if (cbd->owned) + { + if ((cbd == &clip_plus + && get_y_register(PLUS_REGISTER)->y_array != NULL) + || (cbd == &clip_star + && get_y_register(STAR_REGISTER)->y_array != NULL)) + return; + + // Avoid triggering autocmds such as TextYankPost. + block_autocmds(); + + // Get the text between clip_star.start & clip_star.end + old_y_previous = get_y_previous(); + old_y_current = get_y_current(); + old_cursor = curwin->w_cursor; + old_curswant = curwin->w_curswant; + old_set_curswant = curwin->w_set_curswant; + old_op_start = curbuf->b_op_start; + old_op_end = curbuf->b_op_end; + old_visual = VIsual; + old_visual_mode = VIsual_mode; + clear_oparg(&oa); + oa.regname = (cbd == &clip_plus ? '+' : '*'); + oa.op_type = OP_YANK; + CLEAR_FIELD(ca); + ca.oap = &oa; + ca.cmdchar = 'y'; + ca.count1 = 1; + ca.retval = CA_NO_ADJ_OP_END; + do_pending_operator(&ca, 0, TRUE); + + // restore things + set_y_previous(old_y_previous); + set_y_current(old_y_current); + curwin->w_cursor = old_cursor; + changed_cline_bef_curs(); // need to update w_virtcol et al + curwin->w_curswant = old_curswant; + curwin->w_set_curswant = old_set_curswant; + curbuf->b_op_start = old_op_start; + curbuf->b_op_end = old_op_end; + VIsual = old_visual; + VIsual_mode = old_visual_mode; + + unblock_autocmds(); + } + else if (!is_clipboard_needs_update()) + { + clip_free_selection(cbd); + + // Try to get selected text from another window + clip_gen_request_selection(cbd); + } +} + +/* + * Convert from the GUI selection string into the '*'/'+' register. + */ + void +clip_yank_selection( + int type, + char_u *str, + long len, + Clipboard_T *cbd) +{ + yankreg_T *y_ptr; + + if (cbd == &clip_plus) + y_ptr = get_y_register(PLUS_REGISTER); + else + y_ptr = get_y_register(STAR_REGISTER); + + clip_free_selection(cbd); + + str_to_reg(y_ptr, type, str, len, -1, FALSE); +} + +/* + * Convert the '*'/'+' register into a GUI selection string returned in *str + * with length *len. + * Returns the motion type, or -1 for failure. + */ + int +clip_convert_selection(char_u **str, long_u *len, Clipboard_T *cbd) +{ + char_u *p; + int lnum; + int i, j; + int_u eolsize; + yankreg_T *y_ptr; + + if (cbd == &clip_plus) + y_ptr = get_y_register(PLUS_REGISTER); + else + y_ptr = get_y_register(STAR_REGISTER); + +# ifdef USE_CRNL + eolsize = 2; +# else + eolsize = 1; +# endif + + *str = NULL; + *len = 0; + if (y_ptr->y_array == NULL) + return -1; + + for (i = 0; i < y_ptr->y_size; i++) + *len += (long_u)STRLEN(y_ptr->y_array[i]) + eolsize; + + // Don't want newline character at end of last line if we're in MCHAR mode. + if (y_ptr->y_type == MCHAR && *len >= eolsize) + *len -= eolsize; + + p = *str = alloc(*len + 1); // add one to avoid zero + if (p == NULL) + return -1; + lnum = 0; + for (i = 0, j = 0; i < (int)*len; i++, j++) + { + if (y_ptr->y_array[lnum][j] == '\n') + p[i] = NUL; + else if (y_ptr->y_array[lnum][j] == NUL) + { +# ifdef USE_CRNL + p[i++] = '\r'; +# endif + p[i] = '\n'; + lnum++; + j = -1; + } + else + p[i] = y_ptr->y_array[lnum][j]; + } + return y_ptr->y_type; +} + +/* + * When "regname" is a clipboard register, obtain the selection. If it's not + * available return zero, otherwise return "regname". + */ + int +may_get_selection(int regname) +{ + if (regname == '*') + { + if (!clip_star.available) + regname = 0; + else + clip_get_selection(&clip_star); + } + else if (regname == '+') + { + if (!clip_plus.available) + regname = 0; + else + clip_get_selection(&clip_plus); + } + return regname; +} + +/* + * If we have written to a clipboard register, send the text to the clipboard. + */ + void +may_set_selection(void) +{ + if ((get_y_current() == get_y_register(STAR_REGISTER)) + && clip_star.available) + { + clip_own_selection(&clip_star); + clip_gen_set_selection(&clip_star); + } + else if ((get_y_current() == get_y_register(PLUS_REGISTER)) + && clip_plus.available) + { + clip_own_selection(&clip_plus); + clip_gen_set_selection(&clip_plus); + } +} + +/* + * Adjust the register name pointed to with "rp" for the clipboard being + * used always and the clipboard being available. + */ + void +adjust_clip_reg(int *rp) +{ + // If no reg. specified, and "unnamed" or "unnamedplus" is in 'clipboard', + // use '*' or '+' reg, respectively. "unnamedplus" prevails. + if (*rp == 0 && (clip_unnamed != 0 || clip_unnamed_saved != 0)) + { + if (clip_unnamed != 0) + *rp = ((clip_unnamed & CLIP_UNNAMED_PLUS) && clip_plus.available) + ? '+' : '*'; + else + *rp = ((clip_unnamed_saved & CLIP_UNNAMED_PLUS) + && clip_plus.available) ? '+' : '*'; + } + if (!clip_star.available && *rp == '*') + *rp = 0; + if (!clip_plus.available && *rp == '+') + *rp = 0; +} + +#endif // FEAT_CLIPBOARD diff --git a/src/cmdexpand.c b/src/cmdexpand.c new file mode 100644 index 0000000..2366157 --- /dev/null +++ b/src/cmdexpand.c @@ -0,0 +1,4063 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * cmdexpand.c: functions for command-line completion + */ + +#include "vim.h" + +static int cmd_showtail; // Only show path tail in lists ? + +static int ExpandGeneric(char_u *pat, expand_T *xp, regmatch_T *regmatch, + char_u ***matches, int *numMatches, + char_u *((*func)(expand_T *, int)), int escaped); +static int ExpandFromContext(expand_T *xp, char_u *, char_u ***, int *, int); +static char_u *showmatches_gettail(char_u *s); +static int expand_showtail(expand_T *xp); +static int expand_shellcmd(char_u *filepat, char_u ***matches, int *numMatches, int flagsarg); +#if defined(FEAT_EVAL) +static int ExpandUserDefined(char_u *pat, expand_T *xp, regmatch_T *regmatch, char_u ***matches, int *numMatches); +static int ExpandUserList(expand_T *xp, char_u ***matches, int *numMatches); +#endif + +// "compl_match_array" points the currently displayed list of entries in the +// popup menu. It is NULL when there is no popup menu. +static pumitem_T *compl_match_array = NULL; +static int compl_match_arraysize; +// First column in cmdline of the matched item for completion. +static int compl_startcol; +static int compl_selected; + +#define SHOW_MATCH(m) (showtail ? showmatches_gettail(matches[m]) : matches[m]) + +/* + * Returns TRUE if fuzzy completion is supported for a given cmdline completion + * context. + */ + static int +cmdline_fuzzy_completion_supported(expand_T *xp) +{ + return (vim_strchr(p_wop, WOP_FUZZY) != NULL + && xp->xp_context != EXPAND_BOOL_SETTINGS + && xp->xp_context != EXPAND_COLORS + && xp->xp_context != EXPAND_COMPILER + && xp->xp_context != EXPAND_DIRECTORIES + && xp->xp_context != EXPAND_FILES + && xp->xp_context != EXPAND_FILES_IN_PATH + && xp->xp_context != EXPAND_FILETYPE + && xp->xp_context != EXPAND_HELP + && xp->xp_context != EXPAND_OLD_SETTING + && xp->xp_context != EXPAND_OWNSYNTAX + && xp->xp_context != EXPAND_PACKADD + && xp->xp_context != EXPAND_RUNTIME + && xp->xp_context != EXPAND_SHELLCMD + && xp->xp_context != EXPAND_TAGS + && xp->xp_context != EXPAND_TAGS_LISTFILES + && xp->xp_context != EXPAND_USER_LIST); +} + +/* + * Returns TRUE if fuzzy completion for cmdline completion is enabled and + * 'fuzzystr' is not empty. If search pattern is empty, then don't use fuzzy + * matching. + */ + int +cmdline_fuzzy_complete(char_u *fuzzystr) +{ + return vim_strchr(p_wop, WOP_FUZZY) != NULL && *fuzzystr != NUL; +} + +/* + * sort function for the completion matches. + * functions should be sorted to the end. + */ + static int +sort_func_compare(const void *s1, const void *s2) +{ + char_u *p1 = *(char_u **)s1; + char_u *p2 = *(char_u **)s2; + + if (*p1 != '<' && *p2 == '<') return -1; + if (*p1 == '<' && *p2 != '<') return 1; + return STRCMP(p1, p2); +} + +/* + * Escape special characters in the cmdline completion matches. + */ + static void +wildescape( + expand_T *xp, + char_u *str, + int numfiles, + char_u **files) +{ + char_u *p; + int vse_what = xp->xp_context == EXPAND_BUFFERS + ? VSE_BUFFER : VSE_NONE; + + if (xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_FILES_IN_PATH + || xp->xp_context == EXPAND_SHELLCMD + || xp->xp_context == EXPAND_BUFFERS + || xp->xp_context == EXPAND_DIRECTORIES) + { + // Insert a backslash into a file name before a space, \, %, # + // and wildmatch characters, except '~'. + for (int i = 0; i < numfiles; ++i) + { + // for ":set path=" we need to escape spaces twice + if (xp->xp_backslash == XP_BS_THREE) + { + p = vim_strsave_escaped(files[i], (char_u *)" "); + if (p != NULL) + { + vim_free(files[i]); + files[i] = p; +#if defined(BACKSLASH_IN_FILENAME) + p = vim_strsave_escaped(files[i], (char_u *)" "); + if (p != NULL) + { + vim_free(files[i]); + files[i] = p; + } +#endif + } + } +#ifdef BACKSLASH_IN_FILENAME + p = vim_strsave_fnameescape(files[i], vse_what); +#else + p = vim_strsave_fnameescape(files[i], + xp->xp_shell ? VSE_SHELL : vse_what); +#endif + if (p != NULL) + { + vim_free(files[i]); + files[i] = p; + } + + // If 'str' starts with "\~", replace "~" at start of + // files[i] with "\~". + if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~') + escape_fname(&files[i]); + } + xp->xp_backslash = XP_BS_NONE; + + // If the first file starts with a '+' escape it. Otherwise it + // could be seen as "+cmd". + if (*files[0] == '+') + escape_fname(&files[0]); + } + else if (xp->xp_context == EXPAND_TAGS) + { + // Insert a backslash before characters in a tag name that + // would terminate the ":tag" command. + for (int i = 0; i < numfiles; ++i) + { + p = vim_strsave_escaped(files[i], (char_u *)"\\|\""); + if (p != NULL) + { + vim_free(files[i]); + files[i] = p; + } + } + } +} + +/* + * Escape special characters in the cmdline completion matches. + */ + static void +ExpandEscape( + expand_T *xp, + char_u *str, + int numfiles, + char_u **files, + int options) +{ + // May change home directory back to "~" + if (options & WILD_HOME_REPLACE) + tilde_replace(str, numfiles, files); + + if (options & WILD_ESCAPE) + wildescape(xp, str, numfiles, files); +} + +/* + * Return FAIL if this is not an appropriate context in which to do + * completion of anything, return OK if it is (even if there are no matches). + * For the caller, this means that the character is just passed through like a + * normal character (instead of being expanded). This allows :s/^I^D etc. + */ + int +nextwild( + expand_T *xp, + int type, + int options, // extra options for ExpandOne() + int escape) // if TRUE, escape the returned matches +{ + cmdline_info_T *ccline = get_cmdline_info(); + int i, j; + char_u *p1; + char_u *p2; + int difflen; + int v; + + if (xp->xp_numfiles == -1) + { + set_expand_context(xp); + cmd_showtail = expand_showtail(xp); + } + + if (xp->xp_context == EXPAND_UNSUCCESSFUL) + { + beep_flush(); + return OK; // Something illegal on command line + } + if (xp->xp_context == EXPAND_NOTHING) + { + // Caller can use the character as a normal char instead + return FAIL; + } + + // If cmd_silent is set then don't show the dots, because redrawcmd() below + // won't remove them. + if (!cmd_silent) + { + msg_puts("..."); // show that we are busy + out_flush(); + } + + i = (int)(xp->xp_pattern - ccline->cmdbuff); + xp->xp_pattern_len = ccline->cmdpos - i; + + if (type == WILD_NEXT || type == WILD_PREV + || type == WILD_PAGEUP || type == WILD_PAGEDOWN) + { + // Get next/previous match for a previous expanded pattern. + p2 = ExpandOne(xp, NULL, NULL, 0, type); + } + else + { + if (cmdline_fuzzy_completion_supported(xp)) + // If fuzzy matching, don't modify the search string + p1 = vim_strsave(xp->xp_pattern); + else + p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); + + // Translate string into pattern and expand it. + if (p1 == NULL) + p2 = NULL; + else + { + int use_options = options | + WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT; + if (escape) + use_options |= WILD_ESCAPE; + + if (p_wic) + use_options += WILD_ICASE; + p2 = ExpandOne(xp, p1, + vim_strnsave(&ccline->cmdbuff[i], xp->xp_pattern_len), + use_options, type); + vim_free(p1); + // longest match: make sure it is not shorter, happens with :help + if (p2 != NULL && type == WILD_LONGEST) + { + for (j = 0; j < xp->xp_pattern_len; ++j) + if (ccline->cmdbuff[i + j] == '*' + || ccline->cmdbuff[i + j] == '?') + break; + if ((int)STRLEN(p2) < j) + VIM_CLEAR(p2); + } + } + } + + if (p2 != NULL && !got_int) + { + difflen = (int)STRLEN(p2) - xp->xp_pattern_len; + if (ccline->cmdlen + difflen + 4 > ccline->cmdbufflen) + { + v = realloc_cmdbuff(ccline->cmdlen + difflen + 4); + xp->xp_pattern = ccline->cmdbuff + i; + } + else + v = OK; + if (v == OK) + { + mch_memmove(&ccline->cmdbuff[ccline->cmdpos + difflen], + &ccline->cmdbuff[ccline->cmdpos], + (size_t)(ccline->cmdlen - ccline->cmdpos + 1)); + mch_memmove(&ccline->cmdbuff[i], p2, STRLEN(p2)); + ccline->cmdlen += difflen; + ccline->cmdpos += difflen; + } + } + vim_free(p2); + + redrawcmd(); + cursorcmd(); + + // When expanding a ":map" command and no matches are found, assume that + // the key is supposed to be inserted literally + if (xp->xp_context == EXPAND_MAPPINGS && p2 == NULL) + return FAIL; + + if (xp->xp_numfiles <= 0 && p2 == NULL) + beep_flush(); + else if (xp->xp_numfiles == 1) + // free expanded pattern + (void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE); + + return OK; +} + +/* + * Create and display a cmdline completion popup menu with items from + * 'matches'. + */ + static int +cmdline_pum_create( + cmdline_info_T *ccline, + expand_T *xp, + char_u **matches, + int numMatches, + int showtail) +{ + int i; + int columns; + + // Add all the completion matches + compl_match_arraysize = numMatches; + compl_match_array = ALLOC_MULT(pumitem_T, compl_match_arraysize); + for (i = 0; i < numMatches; i++) + { + compl_match_array[i].pum_text = SHOW_MATCH(i); + compl_match_array[i].pum_info = NULL; + compl_match_array[i].pum_extra = NULL; + compl_match_array[i].pum_kind = NULL; + } + + // Compute the popup menu starting column + compl_startcol = vim_strsize(ccline->cmdbuff) + 1; + columns = vim_strsize(xp->xp_pattern); + if (showtail) + { + columns += vim_strsize(showmatches_gettail(matches[0])); + columns -= vim_strsize(matches[0]); + } + if (columns >= compl_startcol) + compl_startcol = 0; + else + compl_startcol -= columns; + + // no default selection + compl_selected = -1; + + cmdline_pum_display(); + + return EXPAND_OK; +} + +/* + * Display the cmdline completion matches in a popup menu + */ + void +cmdline_pum_display(void) +{ + pum_display(compl_match_array, compl_match_arraysize, compl_selected); +} + +/* + * Returns TRUE if the cmdline completion popup menu is being displayed. + */ + int +cmdline_pum_active(void) +{ + return pum_visible() && compl_match_array != NULL; +} + +/* + * Remove the cmdline completion popup menu (if present), free the list of + * items and refresh the screen. + */ + void +cmdline_pum_remove(void) +{ + int save_p_lz = p_lz; + int save_KeyTyped = KeyTyped; + + pum_undisplay(); + VIM_CLEAR(compl_match_array); + p_lz = FALSE; // avoid the popup menu hanging around + update_screen(0); + p_lz = save_p_lz; + redrawcmd(); + + // When a function is called (e.g. for 'foldtext') KeyTyped might be reset + // as a side effect. + KeyTyped = save_KeyTyped; +} + + void +cmdline_pum_cleanup(cmdline_info_T *cclp) +{ + cmdline_pum_remove(); + wildmenu_cleanup(cclp); +} + +/* + * Returns the starting column number to use for the cmdline completion popup + * menu. + */ + int +cmdline_compl_startcol(void) +{ + return compl_startcol; +} + +/* + * Return the number of characters that should be skipped in a status match. + * These are backslashes used for escaping. Do show backslashes in help tags. + */ + static int +skip_status_match_char(expand_T *xp, char_u *s) +{ + if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP) +#ifdef FEAT_MENU + || ((xp->xp_context == EXPAND_MENUS + || xp->xp_context == EXPAND_MENUNAMES) + && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL))) +#endif + ) + { +#ifndef BACKSLASH_IN_FILENAME + if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!') + return 2; +#endif + return 1; + } + return 0; +} + +/* + * Get the length of an item as it will be shown in the status line. + */ + static int +status_match_len(expand_T *xp, char_u *s) +{ + int len = 0; + +#ifdef FEAT_MENU + int emenu = xp->xp_context == EXPAND_MENUS + || xp->xp_context == EXPAND_MENUNAMES; + + // Check for menu separators - replace with '|'. + if (emenu && menu_is_separator(s)) + return 1; +#endif + + while (*s != NUL) + { + s += skip_status_match_char(xp, s); + len += ptr2cells(s); + MB_PTR_ADV(s); + } + + return len; +} + +/* + * Show wildchar matches in the status line. + * Show at least the "match" item. + * We start at item 'first_match' in the list and show all matches that fit. + * + * If inversion is possible we use it. Else '=' characters are used. + */ + static void +win_redr_status_matches( + expand_T *xp, + int num_matches, + char_u **matches, // list of matches + int match, + int showtail) +{ + int row; + char_u *buf; + int len; + int clen; // length in screen cells + int fillchar; + int attr; + int i; + int highlight = TRUE; + char_u *selstart = NULL; + int selstart_col = 0; + char_u *selend = NULL; + static int first_match = 0; + int add_left = FALSE; + char_u *s; +#ifdef FEAT_MENU + int emenu; +#endif + int l; + + if (matches == NULL) // interrupted completion? + return; + + if (has_mbyte) + buf = alloc(Columns * MB_MAXBYTES + 1); + else + buf = alloc(Columns + 1); + if (buf == NULL) + return; + + if (match == -1) // don't show match but original text + { + match = 0; + highlight = FALSE; + } + // count 1 for the ending ">" + clen = status_match_len(xp, SHOW_MATCH(match)) + 3; + if (match == 0) + first_match = 0; + else if (match < first_match) + { + // jumping left, as far as we can go + first_match = match; + add_left = TRUE; + } + else + { + // check if match fits on the screen + for (i = first_match; i < match; ++i) + clen += status_match_len(xp, SHOW_MATCH(i)) + 2; + if (first_match > 0) + clen += 2; + // jumping right, put match at the left + if ((long)clen > Columns) + { + first_match = match; + // if showing the last match, we can add some on the left + clen = 2; + for (i = match; i < num_matches; ++i) + { + clen += status_match_len(xp, SHOW_MATCH(i)) + 2; + if ((long)clen >= Columns) + break; + } + if (i == num_matches) + add_left = TRUE; + } + } + if (add_left) + while (first_match > 0) + { + clen += status_match_len(xp, SHOW_MATCH(first_match - 1)) + 2; + if ((long)clen >= Columns) + break; + --first_match; + } + + fillchar = fillchar_status(&attr, curwin); + + if (first_match == 0) + { + *buf = NUL; + len = 0; + } + else + { + STRCPY(buf, "< "); + len = 2; + } + clen = len; + + i = first_match; + while ((long)(clen + status_match_len(xp, SHOW_MATCH(i)) + 2) < Columns) + { + if (i == match) + { + selstart = buf + len; + selstart_col = clen; + } + + s = SHOW_MATCH(i); + // Check for menu separators - replace with '|' +#ifdef FEAT_MENU + emenu = (xp->xp_context == EXPAND_MENUS + || xp->xp_context == EXPAND_MENUNAMES); + if (emenu && menu_is_separator(s)) + { + STRCPY(buf + len, transchar('|')); + l = (int)STRLEN(buf + len); + len += l; + clen += l; + } + else +#endif + for ( ; *s != NUL; ++s) + { + s += skip_status_match_char(xp, s); + clen += ptr2cells(s); + if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1) + { + STRNCPY(buf + len, s, l); + s += l - 1; + len += l; + } + else + { + STRCPY(buf + len, transchar_byte(*s)); + len += (int)STRLEN(buf + len); + } + } + if (i == match) + selend = buf + len; + + *(buf + len++) = ' '; + *(buf + len++) = ' '; + clen += 2; + if (++i == num_matches) + break; + } + + if (i != num_matches) + { + *(buf + len++) = '>'; + ++clen; + } + + buf[len] = NUL; + + row = cmdline_row - 1; + if (row >= 0) + { + if (wild_menu_showing == 0) + { + if (msg_scrolled > 0) + { + // Put the wildmenu just above the command line. If there is + // no room, scroll the screen one line up. + if (cmdline_row == Rows - 1) + { + screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL); + ++msg_scrolled; + } + else + { + ++cmdline_row; + ++row; + } + wild_menu_showing = WM_SCROLLED; + } + else + { + // Create status line if needed by setting 'laststatus' to 2. + // Set 'winminheight' to zero to avoid that the window is + // resized. + if (lastwin->w_status_height == 0) + { + save_p_ls = p_ls; + save_p_wmh = p_wmh; + p_ls = 2; + p_wmh = 0; + last_status(FALSE); + } + wild_menu_showing = WM_SHOWN; + } + } + + screen_puts(buf, row, 0, attr); + if (selstart != NULL && highlight) + { + *selend = NUL; + screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM)); + } + + screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr); + } + + win_redraw_last_status(topframe); + vim_free(buf); +} + +/* + * Get the next or prev cmdline completion match. The index of the match is set + * in "p_findex" + */ + static char_u * +get_next_or_prev_match( + int mode, + expand_T *xp, + int *p_findex, + char_u *orig_save) +{ + int findex = *p_findex; + int ht; + + if (xp->xp_numfiles <= 0) + return NULL; + + if (mode == WILD_PREV) + { + if (findex == -1) + findex = xp->xp_numfiles; + --findex; + } + else if (mode == WILD_NEXT) + ++findex; + else if (mode == WILD_PAGEUP) + { + if (findex == 0) + // at the first entry, don't select any entries + findex = -1; + else if (findex == -1) + // no entry is selected. select the last entry + findex = xp->xp_numfiles - 1; + else + { + // go up by the pum height + ht = pum_get_height(); + if (ht > 3) + ht -= 2; + findex -= ht; + if (findex < 0) + // few entries left, select the first entry + findex = 0; + } + } + else // mode == WILD_PAGEDOWN + { + if (findex == xp->xp_numfiles - 1) + // at the last entry, don't select any entries + findex = -1; + else if (findex == -1) + // no entry is selected. select the first entry + findex = 0; + else + { + // go down by the pum height + ht = pum_get_height(); + if (ht > 3) + ht -= 2; + findex += ht; + if (findex >= xp->xp_numfiles) + // few entries left, select the last entry + findex = xp->xp_numfiles - 1; + } + } + + // When wrapping around, return the original string, set findex to -1. + if (findex < 0) + { + if (orig_save == NULL) + findex = xp->xp_numfiles - 1; + else + findex = -1; + } + if (findex >= xp->xp_numfiles) + { + if (orig_save == NULL) + findex = 0; + else + findex = -1; + } + if (compl_match_array) + { + compl_selected = findex; + cmdline_pum_display(); + } + else if (p_wmnu) + win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files, + findex, cmd_showtail); + *p_findex = findex; + + if (findex == -1) + return vim_strsave(orig_save); + + return vim_strsave(xp->xp_files[findex]); +} + +/* + * Start the command-line expansion and get the matches. + */ + static char_u * +ExpandOne_start(int mode, expand_T *xp, char_u *str, int options) +{ + int non_suf_match; // number without matching suffix + int i; + char_u *ss = NULL; + + // Do the expansion. + if (ExpandFromContext(xp, str, &xp->xp_files, &xp->xp_numfiles, + options) == FAIL) + { +#ifdef FNAME_ILLEGAL + // Illegal file name has been silently skipped. But when there + // are wildcards, the real problem is that there was no match, + // causing the pattern to be added, which has illegal characters. + if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND)) + semsg(_(e_no_match_str_2), str); +#endif + } + else if (xp->xp_numfiles == 0) + { + if (!(options & WILD_SILENT)) + semsg(_(e_no_match_str_2), str); + } + else + { + // Escape the matches for use on the command line. + ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options); + + // Check for matching suffixes in file names. + if (mode != WILD_ALL && mode != WILD_ALL_KEEP && mode != WILD_LONGEST) + { + if (xp->xp_numfiles) + non_suf_match = xp->xp_numfiles; + else + non_suf_match = 1; + if ((xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_DIRECTORIES) + && xp->xp_numfiles > 1) + { + // More than one match; check suffix. + // The files will have been sorted on matching suffix in + // expand_wildcards, only need to check the first two. + non_suf_match = 0; + for (i = 0; i < 2; ++i) + if (match_suffix(xp->xp_files[i])) + ++non_suf_match; + } + if (non_suf_match != 1) + { + // Can we ever get here unless it's while expanding + // interactively? If not, we can get rid of this all + // together. Don't really want to wait for this message + // (and possibly have to hit return to continue!). + if (!(options & WILD_SILENT)) + emsg(_(e_too_many_file_names)); + else if (!(options & WILD_NO_BEEP)) + beep_flush(); + } + if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE)) + ss = vim_strsave(xp->xp_files[0]); + } + } + + return ss; +} + +/* + * Return the longest common part in the list of cmdline completion matches. + */ + static char_u * +find_longest_match(expand_T *xp, int options) +{ + long_u len; + int mb_len = 1; + int c0, ci; + int i; + char_u *ss; + + for (len = 0; xp->xp_files[0][len]; len += mb_len) + { + if (has_mbyte) + { + mb_len = (*mb_ptr2len)(&xp->xp_files[0][len]); + c0 =(* mb_ptr2char)(&xp->xp_files[0][len]); + } + else + c0 = xp->xp_files[0][len]; + for (i = 1; i < xp->xp_numfiles; ++i) + { + if (has_mbyte) + ci =(* mb_ptr2char)(&xp->xp_files[i][len]); + else + ci = xp->xp_files[i][len]; + if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES + || xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_SHELLCMD + || xp->xp_context == EXPAND_BUFFERS)) + { + if (MB_TOLOWER(c0) != MB_TOLOWER(ci)) + break; + } + else if (c0 != ci) + break; + } + if (i < xp->xp_numfiles) + { + if (!(options & WILD_NO_BEEP)) + vim_beep(BO_WILD); + break; + } + } + + ss = alloc(len + 1); + if (ss) + vim_strncpy(ss, xp->xp_files[0], (size_t)len); + + return ss; +} + +/* + * Do wildcard expansion on the string "str". + * Chars that should not be expanded must be preceded with a backslash. + * Return a pointer to allocated memory containing the new string. + * Return NULL for failure. + * + * "orig" is the originally expanded string, copied to allocated memory. It + * should either be kept in orig_save or freed. When "mode" is WILD_NEXT or + * WILD_PREV "orig" should be NULL. + * + * Results are cached in xp->xp_files and xp->xp_numfiles, except when "mode" + * is WILD_EXPAND_FREE or WILD_ALL. + * + * mode = WILD_FREE: just free previously expanded matches + * mode = WILD_EXPAND_FREE: normal expansion, do not keep matches + * mode = WILD_EXPAND_KEEP: normal expansion, keep matches + * mode = WILD_NEXT: use next match in multiple match, wrap to first + * mode = WILD_PREV: use previous match in multiple match, wrap to first + * mode = WILD_ALL: return all matches concatenated + * mode = WILD_LONGEST: return longest matched part + * mode = WILD_ALL_KEEP: get all matches, keep matches + * mode = WILD_APPLY: apply the item selected in the cmdline completion + * popup menu and close the menu. + * mode = WILD_CANCEL: cancel and close the cmdline completion popup and + * use the original text. + * + * options = WILD_LIST_NOTFOUND: list entries without a match + * options = WILD_HOME_REPLACE: do home_replace() for buffer names + * options = WILD_USE_NL: Use '\n' for WILD_ALL + * options = WILD_NO_BEEP: Don't beep for multiple matches + * options = WILD_ADD_SLASH: add a slash after directory names + * options = WILD_KEEP_ALL: don't remove 'wildignore' entries + * options = WILD_SILENT: don't print warning messages + * options = WILD_ESCAPE: put backslash before special chars + * options = WILD_ICASE: ignore case for files + * options = WILD_ALLLINKS; keep broken links + * + * The variables xp->xp_context and xp->xp_backslash must have been set! + */ + char_u * +ExpandOne( + expand_T *xp, + char_u *str, + char_u *orig, // allocated copy of original of expanded string + int options, + int mode) +{ + char_u *ss = NULL; + static int findex; + static char_u *orig_save = NULL; // kept value of orig + int orig_saved = FALSE; + int i; + long_u len; + + // first handle the case of using an old match + if (mode == WILD_NEXT || mode == WILD_PREV + || mode == WILD_PAGEUP || mode == WILD_PAGEDOWN) + return get_next_or_prev_match(mode, xp, &findex, orig_save); + + if (mode == WILD_CANCEL) + ss = vim_strsave(orig_save ? orig_save : (char_u *)""); + else if (mode == WILD_APPLY) + ss = vim_strsave(findex == -1 ? (orig_save ? + orig_save : (char_u *)"") : xp->xp_files[findex]); + + // free old names + if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST) + { + FreeWild(xp->xp_numfiles, xp->xp_files); + xp->xp_numfiles = -1; + VIM_CLEAR(orig_save); + + // The entries from xp_files may be used in the PUM, remove it. + if (compl_match_array != NULL) + cmdline_pum_remove(); + } + findex = 0; + + if (mode == WILD_FREE) // only release file name + return NULL; + + if (xp->xp_numfiles == -1 && mode != WILD_APPLY && mode != WILD_CANCEL) + { + vim_free(orig_save); + orig_save = orig; + orig_saved = TRUE; + + ss = ExpandOne_start(mode, xp, str, options); + } + + // Find longest common part + if (mode == WILD_LONGEST && xp->xp_numfiles > 0) + { + ss = find_longest_match(xp, options); + findex = -1; // next p_wc gets first one + } + + // Concatenate all matching names. Unless interrupted, this can be slow + // and the result probably won't be used. + if (mode == WILD_ALL && xp->xp_numfiles > 0 && !got_int) + { + len = 0; + for (i = 0; i < xp->xp_numfiles; ++i) + len += (long_u)STRLEN(xp->xp_files[i]) + 1; + ss = alloc(len); + if (ss != NULL) + { + *ss = NUL; + for (i = 0; i < xp->xp_numfiles; ++i) + { + STRCAT(ss, xp->xp_files[i]); + if (i != xp->xp_numfiles - 1) + STRCAT(ss, (options & WILD_USE_NL) ? "\n" : " "); + } + } + } + + if (mode == WILD_EXPAND_FREE || mode == WILD_ALL) + ExpandCleanup(xp); + + // Free "orig" if it wasn't stored in "orig_save". + if (!orig_saved) + vim_free(orig); + + return ss; +} + +/* + * Prepare an expand structure for use. + */ + void +ExpandInit(expand_T *xp) +{ + CLEAR_POINTER(xp); + xp->xp_backslash = XP_BS_NONE; + xp->xp_numfiles = -1; +} + +/* + * Cleanup an expand structure after use. + */ + void +ExpandCleanup(expand_T *xp) +{ + if (xp->xp_numfiles >= 0) + { + FreeWild(xp->xp_numfiles, xp->xp_files); + xp->xp_numfiles = -1; + } +} + +/* + * Display one line of completion matches. Multiple matches are displayed in + * each line (used by wildmode=list and CTRL-D) + * matches - list of completion match names + * numMatches - number of completion matches in "matches" + * lines - number of output lines + * linenr - line number of matches to display + * maxlen - maximum number of characters in each line + * showtail - display only the tail of the full path of a file name + * dir_attr - highlight attribute to use for directory names + */ + static void +showmatches_oneline( + expand_T *xp, + char_u **matches, + int numMatches, + int lines, + int linenr, + int maxlen, + int showtail, + int dir_attr) +{ + int i, j; + int isdir; + int lastlen; + char_u *p; + + lastlen = 999; + for (j = linenr; j < numMatches; j += lines) + { + if (xp->xp_context == EXPAND_TAGS_LISTFILES) + { + msg_outtrans_attr(matches[j], HL_ATTR(HLF_D)); + p = matches[j] + STRLEN(matches[j]) + 1; + msg_advance(maxlen + 1); + msg_puts((char *)p); + msg_advance(maxlen + 3); + msg_outtrans_long_attr(p + 2, HL_ATTR(HLF_D)); + break; + } + for (i = maxlen - lastlen; --i >= 0; ) + msg_putchar(' '); + if (xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_SHELLCMD + || xp->xp_context == EXPAND_BUFFERS) + { + // highlight directories + if (xp->xp_numfiles != -1) + { + char_u *halved_slash; + char_u *exp_path; + char_u *path; + + // Expansion was done before and special characters + // were escaped, need to halve backslashes. Also + // $HOME has been replaced with ~/. + exp_path = expand_env_save_opt(matches[j], TRUE); + path = exp_path != NULL ? exp_path : matches[j]; + halved_slash = backslash_halve_save(path); + isdir = mch_isdir(halved_slash != NULL ? halved_slash + : matches[j]); + vim_free(exp_path); + if (halved_slash != path) + vim_free(halved_slash); + } + else + // Expansion was done here, file names are literal. + isdir = mch_isdir(matches[j]); + if (showtail) + p = SHOW_MATCH(j); + else + { + home_replace(NULL, matches[j], NameBuff, MAXPATHL, + TRUE); + p = NameBuff; + } + } + else + { + isdir = FALSE; + p = SHOW_MATCH(j); + } + lastlen = msg_outtrans_attr(p, isdir ? dir_attr : 0); + } + if (msg_col > 0) // when not wrapped around + { + msg_clr_eos(); + msg_putchar('\n'); + } + out_flush(); // show one line at a time +} + +/* + * Show all matches for completion on the command line. + * Returns EXPAND_NOTHING when the character that triggered expansion should + * be inserted like a normal character. + */ + int +showmatches(expand_T *xp, int wildmenu UNUSED) +{ + cmdline_info_T *ccline = get_cmdline_info(); + int numMatches; + char_u **matches; + int i, j; + int maxlen; + int lines; + int columns; + int attr; + int showtail; + + if (xp->xp_numfiles == -1) + { + set_expand_context(xp); + i = expand_cmdline(xp, ccline->cmdbuff, ccline->cmdpos, + &numMatches, &matches); + showtail = expand_showtail(xp); + if (i != EXPAND_OK) + return i; + } + else + { + numMatches = xp->xp_numfiles; + matches = xp->xp_files; + showtail = cmd_showtail; + } + + if (wildmenu && vim_strchr(p_wop, WOP_PUM) != NULL) + // cmdline completion popup menu (with wildoptions=pum) + return cmdline_pum_create(ccline, xp, matches, numMatches, showtail); + + if (!wildmenu) + { + msg_didany = FALSE; // lines_left will be set + msg_start(); // prepare for paging + msg_putchar('\n'); + out_flush(); + cmdline_row = msg_row; + msg_didany = FALSE; // lines_left will be set again + msg_start(); // prepare for paging + } + + if (got_int) + got_int = FALSE; // only int. the completion, not the cmd line + else if (wildmenu) + win_redr_status_matches(xp, numMatches, matches, -1, showtail); + else + { + // find the length of the longest file name + maxlen = 0; + for (i = 0; i < numMatches; ++i) + { + if (!showtail && (xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_SHELLCMD + || xp->xp_context == EXPAND_BUFFERS)) + { + home_replace(NULL, matches[i], NameBuff, MAXPATHL, TRUE); + j = vim_strsize(NameBuff); + } + else + j = vim_strsize(SHOW_MATCH(i)); + if (j > maxlen) + maxlen = j; + } + + if (xp->xp_context == EXPAND_TAGS_LISTFILES) + lines = numMatches; + else + { + // compute the number of columns and lines for the listing + maxlen += 2; // two spaces between file names + columns = ((int)Columns + 2) / maxlen; + if (columns < 1) + columns = 1; + lines = (numMatches + columns - 1) / columns; + } + + attr = HL_ATTR(HLF_D); // find out highlighting for directories + + if (xp->xp_context == EXPAND_TAGS_LISTFILES) + { + msg_puts_attr(_("tagname"), HL_ATTR(HLF_T)); + msg_clr_eos(); + msg_advance(maxlen - 3); + msg_puts_attr(_(" kind file\n"), HL_ATTR(HLF_T)); + } + + // list the files line by line + for (i = 0; i < lines; ++i) + { + showmatches_oneline(xp, matches, numMatches, lines, i, + maxlen, showtail, attr); + if (got_int) + { + got_int = FALSE; + break; + } + } + + // we redraw the command below the lines that we have just listed + // This is a bit tricky, but it saves a lot of screen updating. + cmdline_row = msg_row; // will put it back later + } + + if (xp->xp_numfiles == -1) + FreeWild(numMatches, matches); + + return EXPAND_OK; +} + +/* + * gettail() version for showmatches() and win_redr_status_matches(): + * Return the tail of file name path "s", ignoring a trailing "/". + */ + static char_u * +showmatches_gettail(char_u *s) +{ + char_u *p; + char_u *t = s; + int had_sep = FALSE; + + for (p = s; *p != NUL; ) + { + if (vim_ispathsep(*p) +#ifdef BACKSLASH_IN_FILENAME + && !rem_backslash(p) +#endif + ) + had_sep = TRUE; + else if (had_sep) + { + t = p; + had_sep = FALSE; + } + MB_PTR_ADV(p); + } + return t; +} + +/* + * Return TRUE if we only need to show the tail of completion matches. + * When not completing file names or there is a wildcard in the path FALSE is + * returned. + */ + static int +expand_showtail(expand_T *xp) +{ + char_u *s; + char_u *end; + + // When not completing file names a "/" may mean something different. + if (xp->xp_context != EXPAND_FILES + && xp->xp_context != EXPAND_SHELLCMD + && xp->xp_context != EXPAND_DIRECTORIES) + return FALSE; + + end = gettail(xp->xp_pattern); + if (end == xp->xp_pattern) // there is no path separator + return FALSE; + + for (s = xp->xp_pattern; s < end; s++) + { + // Skip escaped wildcards. Only when the backslash is not a path + // separator, on DOS the '*' "path\*\file" must not be skipped. + if (rem_backslash(s)) + ++s; + else if (vim_strchr((char_u *)"*?[", *s) != NULL) + return FALSE; + } + return TRUE; +} + +/* + * Prepare a string for expansion. + * When expanding file names: The string will be used with expand_wildcards(). + * Copy "fname[len]" into allocated memory and add a '*' at the end. + * When expanding other names: The string will be used with regcomp(). Copy + * the name into allocated memory and prepend "^". + */ + char_u * +addstar( + char_u *fname, + int len, + int context) // EXPAND_FILES etc. +{ + char_u *retval; + int i, j; + int new_len; + char_u *tail; + int ends_in_star; + + if (context != EXPAND_FILES + && context != EXPAND_FILES_IN_PATH + && context != EXPAND_SHELLCMD + && context != EXPAND_DIRECTORIES) + { + // Matching will be done internally (on something other than files). + // So we convert the file-matching-type wildcards into our kind for + // use with vim_regcomp(). First work out how long it will be: + + // For help tags the translation is done in find_help_tags(). + // For a tag pattern starting with "/" no translation is needed. + if (context == EXPAND_HELP + || context == EXPAND_COLORS + || context == EXPAND_COMPILER + || context == EXPAND_OWNSYNTAX + || context == EXPAND_FILETYPE + || context == EXPAND_PACKADD + || context == EXPAND_RUNTIME + || ((context == EXPAND_TAGS_LISTFILES + || context == EXPAND_TAGS) + && fname[0] == '/')) + retval = vim_strnsave(fname, len); + else + { + new_len = len + 2; // +2 for '^' at start, NUL at end + for (i = 0; i < len; i++) + { + if (fname[i] == '*' || fname[i] == '~') + new_len++; // '*' needs to be replaced by ".*" + // '~' needs to be replaced by "\~" + + // Buffer names are like file names. "." should be literal + if (context == EXPAND_BUFFERS && fname[i] == '.') + new_len++; // "." becomes "\." + + // Custom expansion takes care of special things, match + // backslashes literally (perhaps also for other types?) + if ((context == EXPAND_USER_DEFINED + || context == EXPAND_USER_LIST) && fname[i] == '\\') + new_len++; // '\' becomes "\\" + } + retval = alloc(new_len); + if (retval != NULL) + { + retval[0] = '^'; + j = 1; + for (i = 0; i < len; i++, j++) + { + // Skip backslash. But why? At least keep it for custom + // expansion. + if (context != EXPAND_USER_DEFINED + && context != EXPAND_USER_LIST + && fname[i] == '\\' + && ++i == len) + break; + + switch (fname[i]) + { + case '*': retval[j++] = '.'; + break; + case '~': retval[j++] = '\\'; + break; + case '?': retval[j] = '.'; + continue; + case '.': if (context == EXPAND_BUFFERS) + retval[j++] = '\\'; + break; + case '\\': if (context == EXPAND_USER_DEFINED + || context == EXPAND_USER_LIST) + retval[j++] = '\\'; + break; + } + retval[j] = fname[i]; + } + retval[j] = NUL; + } + } + } + else + { + retval = alloc(len + 4); + if (retval != NULL) + { + vim_strncpy(retval, fname, len); + + // Don't add a star to *, ~, ~user, $var or `cmd`. + // * would become **, which walks the whole tree. + // ~ would be at the start of the file name, but not the tail. + // $ could be anywhere in the tail. + // ` could be anywhere in the file name. + // When the name ends in '$' don't add a star, remove the '$'. + tail = gettail(retval); + ends_in_star = (len > 0 && retval[len - 1] == '*'); +#ifndef BACKSLASH_IN_FILENAME + for (i = len - 2; i >= 0; --i) + { + if (retval[i] != '\\') + break; + ends_in_star = !ends_in_star; + } +#endif + if ((*retval != '~' || tail != retval) + && !ends_in_star + && vim_strchr(tail, '$') == NULL + && vim_strchr(retval, '`') == NULL) + retval[len++] = '*'; + else if (len > 0 && retval[len - 1] == '$') + --len; + retval[len] = NUL; + } + } + return retval; +} + +/* + * Must parse the command line so far to work out what context we are in. + * Completion can then be done based on that context. + * This routine sets the variables: + * xp->xp_pattern The start of the pattern to be expanded within + * the command line (ends at the cursor). + * xp->xp_context The type of thing to expand. Will be one of: + * + * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on + * the command line, like an unknown command. Caller + * should beep. + * EXPAND_NOTHING Unrecognised context for completion, use char like + * a normal char, rather than for completion. eg + * :s/^I/ + * EXPAND_COMMANDS Cursor is still touching the command, so complete + * it. + * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands. + * EXPAND_FILES After command with EX_XFILE set, or after setting + * with P_EXPAND set. eg :e ^I, :w>>^I + * EXPAND_DIRECTORIES In some cases this is used instead of the latter + * when we know only directories are of interest. eg + * :set dir=^I + * EXPAND_SHELLCMD After ":!cmd", ":r !cmd" or ":w !cmd". + * EXPAND_SETTINGS Complete variable names. eg :set d^I + * EXPAND_BOOL_SETTINGS Complete boolean variables only, eg :set no^I + * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I + * EXPAND_TAGS_LISTFILES As above, but list filenames on ^D, after :tselect + * EXPAND_HELP Complete tags from the file 'helpfile'/tags + * EXPAND_EVENTS Complete event names + * EXPAND_SYNTAX Complete :syntax command arguments + * EXPAND_HIGHLIGHT Complete highlight (syntax) group names + * EXPAND_AUGROUP Complete autocommand group names + * EXPAND_USER_VARS Complete user defined variable names, eg :unlet a^I + * EXPAND_MAPPINGS Complete mapping and abbreviation names, + * eg :unmap a^I , :cunab x^I + * EXPAND_FUNCTIONS Complete internal or user defined function names, + * eg :call sub^I + * EXPAND_USER_FUNC Complete user defined function names, eg :delf F^I + * EXPAND_EXPRESSION Complete internal or user defined function/variable + * names in expressions, eg :while s^I + * EXPAND_ENV_VARS Complete environment variable names + * EXPAND_USER Complete user names + */ + void +set_expand_context(expand_T *xp) +{ + cmdline_info_T *ccline = get_cmdline_info(); + + // only expansion for ':', '>' and '=' command-lines + if (ccline->cmdfirstc != ':' +#ifdef FEAT_EVAL + && ccline->cmdfirstc != '>' && ccline->cmdfirstc != '=' + && !ccline->input_fn +#endif + ) + { + xp->xp_context = EXPAND_NOTHING; + return; + } + set_cmd_context(xp, ccline->cmdbuff, ccline->cmdlen, ccline->cmdpos, TRUE); +} + +/* + * Sets the index of a built-in or user defined command 'cmd' in eap->cmdidx. + * For user defined commands, the completion context is set in 'xp' and the + * completion flags in 'complp'. + * + * Returns a pointer to the text after the command or NULL for failure. + */ + static char_u * +set_cmd_index(char_u *cmd, exarg_T *eap, expand_T *xp, int *complp) +{ + char_u *p = NULL; + int len = 0; + int fuzzy = cmdline_fuzzy_complete(cmd); + + // Isolate the command and search for it in the command table. + // Exceptions: + // - the 'k' command can directly be followed by any character, but do + // accept "keepmarks", "keepalt" and "keepjumps". As fuzzy matching can + // find matches anywhere in the command name, do this only for command + // expansion based on regular expression and not for fuzzy matching. + // - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' + if (!fuzzy && (*cmd == 'k' && cmd[1] != 'e')) + { + eap->cmdidx = CMD_k; + p = cmd + 1; + } + else + { + p = cmd; + while (ASCII_ISALPHA(*p) || *p == '*') // Allow * wild card + ++p; + // A user command may contain digits. + // Include "9" for "vim9*" commands; "vim9cmd" and "vim9script". + if (ASCII_ISUPPER(cmd[0]) || STRNCMP("vim9", cmd, 4) == 0) + while (ASCII_ISALNUM(*p) || *p == '*') + ++p; + // for python 3.x: ":py3*" commands completion + if (cmd[0] == 'p' && cmd[1] == 'y' && p == cmd + 2 && *p == '3') + { + ++p; + while (ASCII_ISALPHA(*p) || *p == '*') + ++p; + } + // check for non-alpha command + if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL) + ++p; + len = (int)(p - cmd); + + if (len == 0) + { + xp->xp_context = EXPAND_UNSUCCESSFUL; + return NULL; + } + + eap->cmdidx = excmd_get_cmdidx(cmd, len); + + // User defined commands support alphanumeric characters. + // Also when doing fuzzy expansion for non-shell commands, support + // alphanumeric characters. + if ((cmd[0] >= 'A' && cmd[0] <= 'Z') + || (fuzzy && eap->cmdidx != CMD_bang && *p != NUL)) + while (ASCII_ISALNUM(*p) || *p == '*') // Allow * wild card + ++p; + } + + // If the cursor is touching the command, and it ends in an alphanumeric + // character, complete the command name. + if (*p == NUL && ASCII_ISALNUM(p[-1])) + return NULL; + + if (eap->cmdidx == CMD_SIZE) + { + if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL) + { + eap->cmdidx = CMD_substitute; + p = cmd + 1; + } + else if (cmd[0] >= 'A' && cmd[0] <= 'Z') + { + eap->cmd = cmd; + p = find_ucmd(eap, p, NULL, xp, complp); + if (p == NULL) + eap->cmdidx = CMD_SIZE; // ambiguous user command + } + } + if (eap->cmdidx == CMD_SIZE) + { + // Not still touching the command and it was an illegal one + xp->xp_context = EXPAND_UNSUCCESSFUL; + return NULL; + } + + return p; +} + +/* + * Set the completion context for a command argument with wild card characters. + */ + static void +set_context_for_wildcard_arg( + exarg_T *eap, + char_u *arg, + int usefilter, + expand_T *xp, + int *complp) +{ + char_u *p; + int c; + int in_quote = FALSE; + char_u *bow = NULL; // Beginning of word + int len = 0; + + // Allow spaces within back-quotes to count as part of the argument + // being expanded. + xp->xp_pattern = skipwhite(arg); + p = xp->xp_pattern; + while (*p != NUL) + { + if (has_mbyte) + c = mb_ptr2char(p); + else + c = *p; + if (c == '\\' && p[1] != NUL) + ++p; + else if (c == '`') + { + if (!in_quote) + { + xp->xp_pattern = p; + bow = p + 1; + } + in_quote = !in_quote; + } + // An argument can contain just about everything, except + // characters that end the command and white space. + else if (c == '|' || c == '\n' || c == '"' || (VIM_ISWHITE(c) +#ifdef SPACE_IN_FILENAME + && (!(eap->argt & EX_NOSPC) || usefilter) +#endif + )) + { + len = 0; // avoid getting stuck when space is in 'isfname' + while (*p != NUL) + { + if (has_mbyte) + c = mb_ptr2char(p); + else + c = *p; + if (c == '`' || vim_isfilec_or_wc(c)) + break; + if (has_mbyte) + len = (*mb_ptr2len)(p); + else + len = 1; + MB_PTR_ADV(p); + } + if (in_quote) + bow = p; + else + xp->xp_pattern = p; + p -= len; + } + MB_PTR_ADV(p); + } + + // If we are still inside the quotes, and we passed a space, just + // expand from there. + if (bow != NULL && in_quote) + xp->xp_pattern = bow; + xp->xp_context = EXPAND_FILES; + + // For a shell command more chars need to be escaped. + if (usefilter || eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal) + { +#ifndef BACKSLASH_IN_FILENAME + xp->xp_shell = TRUE; +#endif + // When still after the command name expand executables. + if (xp->xp_pattern == skipwhite(arg)) + xp->xp_context = EXPAND_SHELLCMD; + } + + // Check for environment variable. + if (*xp->xp_pattern == '$') + { + for (p = xp->xp_pattern + 1; *p != NUL; ++p) + if (!vim_isIDc(*p)) + break; + if (*p == NUL) + { + xp->xp_context = EXPAND_ENV_VARS; + ++xp->xp_pattern; + // Avoid that the assignment uses EXPAND_FILES again. + if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST) + *complp = EXPAND_ENV_VARS; + } + } + // Check for user names. + if (*xp->xp_pattern == '~') + { + for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p) + ; + // Complete ~user only if it partially matches a user name. + // A full match ~user will be replaced by user's home + // directory i.e. something like ~user -> /home/user/ + if (*p == NUL && p > xp->xp_pattern + 1 + && match_user(xp->xp_pattern + 1) >= 1) + { + xp->xp_context = EXPAND_USER; + ++xp->xp_pattern; + } + } +} + +/* + * Set the completion context for the :filter command. Returns a pointer to the + * next command after the :filter command. + */ + static char_u * +set_context_in_filter_cmd(expand_T *xp, char_u *arg) +{ + if (*arg != NUL) + arg = skip_vimgrep_pat(arg, NULL, NULL); + if (arg == NULL || *arg == NUL) + { + xp->xp_context = EXPAND_NOTHING; + return NULL; + } + return skipwhite(arg); +} + +#ifdef FEAT_SEARCH_EXTRA +/* + * Set the completion context for the :match command. Returns a pointer to the + * next command after the :match command. + */ + static char_u * +set_context_in_match_cmd(expand_T *xp, char_u *arg) +{ + if (*arg == NUL || !ends_excmd(*arg)) + { + // also complete "None" + set_context_in_echohl_cmd(xp, arg); + arg = skipwhite(skiptowhite(arg)); + if (*arg != NUL) + { + xp->xp_context = EXPAND_NOTHING; + arg = skip_regexp(arg + 1, *arg, magic_isset()); + } + } + return find_nextcmd(arg); +} +#endif + +/* + * Returns a pointer to the next command after a :global or a :v command. + * Returns NULL if there is no next command. + */ + static char_u * +find_cmd_after_global_cmd(char_u *arg) +{ + int delim; + + delim = *arg; // get the delimiter + if (delim) + ++arg; // skip delimiter if there is one + + while (arg[0] != NUL && arg[0] != delim) + { + if (arg[0] == '\\' && arg[1] != NUL) + ++arg; + ++arg; + } + if (arg[0] != NUL) + return arg + 1; + + return NULL; +} + +/* + * Returns a pointer to the next command after a :substitute or a :& command. + * Returns NULL if there is no next command. + */ + static char_u * +find_cmd_after_substitute_cmd(char_u *arg) +{ + int delim; + + delim = *arg; + if (delim) + { + // skip "from" part + ++arg; + arg = skip_regexp(arg, delim, magic_isset()); + + if (arg[0] != NUL && arg[0] == delim) + { + // skip "to" part + ++arg; + while (arg[0] != NUL && arg[0] != delim) + { + if (arg[0] == '\\' && arg[1] != NUL) + ++arg; + ++arg; + } + if (arg[0] != NUL) // skip delimiter + ++arg; + } + } + while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL) + ++arg; + if (arg[0] != NUL) + return arg; + + return NULL; +} + +/* + * Returns a pointer to the next command after a :isearch/:dsearch/:ilist + * :dlist/:ijump/:psearch/:djump/:isplit/:dsplit command. + * Returns NULL if there is no next command. + */ + static char_u * +find_cmd_after_isearch_cmd(expand_T *xp, char_u *arg) +{ + arg = skipwhite(skipdigits(arg)); // skip count + if (*arg != '/') + return NULL; + + // Match regexp, not just whole words + for (++arg; *arg && *arg != '/'; arg++) + if (*arg == '\\' && arg[1] != NUL) + arg++; + if (*arg) + { + arg = skipwhite(arg + 1); + + // Check for trailing illegal characters + if (*arg == NUL || vim_strchr((char_u *)"|\"\n", *arg) == NULL) + xp->xp_context = EXPAND_NOTHING; + else + return arg; + } + + return NULL; +} + +#ifdef FEAT_EVAL +/* + * Set the completion context for the :unlet command. Always returns NULL. + */ + static char_u * +set_context_in_unlet_cmd(expand_T *xp, char_u *arg) +{ + while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) + arg = xp->xp_pattern + 1; + + xp->xp_context = EXPAND_USER_VARS; + xp->xp_pattern = arg; + + if (*xp->xp_pattern == '$') + { + xp->xp_context = EXPAND_ENV_VARS; + ++xp->xp_pattern; + } + + return NULL; +} +#endif + +#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) +/* + * Set the completion context for the :language command. Always returns NULL. + */ + static char_u * +set_context_in_lang_cmd(expand_T *xp, char_u *arg) +{ + char_u *p; + + p = skiptowhite(arg); + if (*p == NUL) + { + xp->xp_context = EXPAND_LANGUAGE; + xp->xp_pattern = arg; + } + else + { + if ( STRNCMP(arg, "messages", p - arg) == 0 + || STRNCMP(arg, "ctype", p - arg) == 0 + || STRNCMP(arg, "time", p - arg) == 0 + || STRNCMP(arg, "collate", p - arg) == 0) + { + xp->xp_context = EXPAND_LOCALES; + xp->xp_pattern = skipwhite(p); + } + else + xp->xp_context = EXPAND_NOTHING; + } + + return NULL; +} +#endif + +#ifdef FEAT_EVAL +static enum +{ + EXP_BREAKPT_ADD, // expand ":breakadd" sub-commands + EXP_BREAKPT_DEL, // expand ":breakdel" sub-commands + EXP_PROFDEL // expand ":profdel" sub-commands +} breakpt_expand_what; + +/* + * Set the completion context for the :breakadd command. Always returns NULL. + */ + static char_u * +set_context_in_breakadd_cmd(expand_T *xp, char_u *arg, cmdidx_T cmdidx) +{ + char_u *p; + char_u *subcmd_start; + + xp->xp_context = EXPAND_BREAKPOINT; + xp->xp_pattern = arg; + + if (cmdidx == CMD_breakadd) + breakpt_expand_what = EXP_BREAKPT_ADD; + else if (cmdidx == CMD_breakdel) + breakpt_expand_what = EXP_BREAKPT_DEL; + else + breakpt_expand_what = EXP_PROFDEL; + + p = skipwhite(arg); + if (*p == NUL) + return NULL; + subcmd_start = p; + + if (STRNCMP("file ", p, 5) == 0 || STRNCMP("func ", p, 5) == 0) + { + // :breakadd file [lnum] + // :breakadd func [lnum] + p += 4; + p = skipwhite(p); + + // skip line number (if specified) + if (VIM_ISDIGIT(*p)) + { + p = skipdigits(p); + if (*p != ' ') + { + xp->xp_context = EXPAND_NOTHING; + return NULL; + } + p = skipwhite(p); + } + if (STRNCMP("file", subcmd_start, 4) == 0) + xp->xp_context = EXPAND_FILES; + else + xp->xp_context = EXPAND_USER_FUNC; + xp->xp_pattern = p; + } + else if (STRNCMP("expr ", p, 5) == 0) + { + // :breakadd expr + xp->xp_context = EXPAND_EXPRESSION; + xp->xp_pattern = skipwhite(p + 5); + } + + return NULL; +} + + static char_u * +set_context_in_scriptnames_cmd(expand_T *xp, char_u *arg) +{ + char_u *p; + + xp->xp_context = EXPAND_NOTHING; + xp->xp_pattern = NULL; + + p = skipwhite(arg); + if (VIM_ISDIGIT(*p)) + return NULL; + + xp->xp_context = EXPAND_SCRIPTNAMES; + xp->xp_pattern = p; + + return NULL; +} +#endif + +/* + * Set the completion context in 'xp' for command 'cmd' with index 'cmdidx'. + * The argument to the command is 'arg' and the argument flags is 'argt'. + * For user-defined commands and for environment variables, 'compl' has the + * completion type. + * Returns a pointer to the next command. Returns NULL if there is no next + * command. + */ + static char_u * +set_context_by_cmdname( + char_u *cmd, + cmdidx_T cmdidx, + expand_T *xp, + char_u *arg, + long argt, + int compl, + int forceit) +{ + switch (cmdidx) + { + case CMD_find: + case CMD_sfind: + case CMD_tabfind: + if (xp->xp_context == EXPAND_FILES) + xp->xp_context = EXPAND_FILES_IN_PATH; + break; + case CMD_cd: + case CMD_chdir: + case CMD_tcd: + case CMD_tchdir: + case CMD_lcd: + case CMD_lchdir: + if (xp->xp_context == EXPAND_FILES) + xp->xp_context = EXPAND_DIRECTORIES; + break; + case CMD_help: + xp->xp_context = EXPAND_HELP; + xp->xp_pattern = arg; + break; + + // Command modifiers: return the argument. + // Also for commands with an argument that is a command. + case CMD_aboveleft: + case CMD_argdo: + case CMD_belowright: + case CMD_botright: + case CMD_browse: + case CMD_bufdo: + case CMD_cdo: + case CMD_cfdo: + case CMD_confirm: + case CMD_debug: + case CMD_folddoclosed: + case CMD_folddoopen: + case CMD_hide: + case CMD_horizontal: + case CMD_keepalt: + case CMD_keepjumps: + case CMD_keepmarks: + case CMD_keeppatterns: + case CMD_ldo: + case CMD_leftabove: + case CMD_lfdo: + case CMD_lockmarks: + case CMD_noautocmd: + case CMD_noswapfile: + case CMD_rightbelow: + case CMD_sandbox: + case CMD_silent: + case CMD_tab: + case CMD_tabdo: + case CMD_topleft: + case CMD_verbose: + case CMD_vertical: + case CMD_windo: + case CMD_vim9cmd: + case CMD_legacy: + return arg; + + case CMD_filter: + return set_context_in_filter_cmd(xp, arg); + +#ifdef FEAT_SEARCH_EXTRA + case CMD_match: + return set_context_in_match_cmd(xp, arg); +#endif + + // All completion for the +cmdline_compl feature goes here. + + case CMD_command: + return set_context_in_user_cmd(xp, arg); + + case CMD_delcommand: + xp->xp_context = EXPAND_USER_COMMANDS; + xp->xp_pattern = arg; + break; + + case CMD_global: + case CMD_vglobal: + return find_cmd_after_global_cmd(arg); + case CMD_and: + case CMD_substitute: + return find_cmd_after_substitute_cmd(arg); + case CMD_isearch: + case CMD_dsearch: + case CMD_ilist: + case CMD_dlist: + case CMD_ijump: + case CMD_psearch: + case CMD_djump: + case CMD_isplit: + case CMD_dsplit: + return find_cmd_after_isearch_cmd(xp, arg); + case CMD_autocmd: + return set_context_in_autocmd(xp, arg, FALSE); + case CMD_doautocmd: + case CMD_doautoall: + return set_context_in_autocmd(xp, arg, TRUE); + case CMD_set: + set_context_in_set_cmd(xp, arg, 0); + break; + case CMD_setglobal: + set_context_in_set_cmd(xp, arg, OPT_GLOBAL); + break; + case CMD_setlocal: + set_context_in_set_cmd(xp, arg, OPT_LOCAL); + break; + case CMD_tag: + case CMD_stag: + case CMD_ptag: + case CMD_ltag: + case CMD_tselect: + case CMD_stselect: + case CMD_ptselect: + case CMD_tjump: + case CMD_stjump: + case CMD_ptjump: + if (vim_strchr(p_wop, WOP_TAGFILE) != NULL) + xp->xp_context = EXPAND_TAGS_LISTFILES; + else + xp->xp_context = EXPAND_TAGS; + xp->xp_pattern = arg; + break; + case CMD_augroup: + xp->xp_context = EXPAND_AUGROUP; + xp->xp_pattern = arg; + break; +#ifdef FEAT_SYN_HL + case CMD_syntax: + set_context_in_syntax_cmd(xp, arg); + break; +#endif +#ifdef FEAT_EVAL + case CMD_final: + case CMD_const: + case CMD_let: + case CMD_var: + case CMD_if: + case CMD_elseif: + case CMD_while: + case CMD_for: + case CMD_echo: + case CMD_echon: + case CMD_execute: + case CMD_echomsg: + case CMD_echoerr: + case CMD_call: + case CMD_return: + case CMD_cexpr: + case CMD_caddexpr: + case CMD_cgetexpr: + case CMD_lexpr: + case CMD_laddexpr: + case CMD_lgetexpr: + set_context_for_expression(xp, arg, cmdidx); + break; + + case CMD_unlet: + return set_context_in_unlet_cmd(xp, arg); + case CMD_function: + case CMD_delfunction: + xp->xp_context = EXPAND_USER_FUNC; + xp->xp_pattern = arg; + break; + case CMD_disassemble: + set_context_in_disassemble_cmd(xp, arg); + break; + + case CMD_echohl: + set_context_in_echohl_cmd(xp, arg); + break; +#endif + case CMD_highlight: + set_context_in_highlight_cmd(xp, arg); + break; +#ifdef FEAT_CSCOPE + case CMD_cscope: + case CMD_lcscope: + case CMD_scscope: + set_context_in_cscope_cmd(xp, arg, cmdidx); + break; +#endif +#ifdef FEAT_SIGNS + case CMD_sign: + set_context_in_sign_cmd(xp, arg); + break; +#endif + case CMD_bdelete: + case CMD_bwipeout: + case CMD_bunload: + while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) + arg = xp->xp_pattern + 1; + // FALLTHROUGH + case CMD_buffer: + case CMD_sbuffer: + case CMD_checktime: + xp->xp_context = EXPAND_BUFFERS; + xp->xp_pattern = arg; + break; +#ifdef FEAT_DIFF + case CMD_diffget: + case CMD_diffput: + // If current buffer is in diff mode, complete buffer names + // which are in diff mode, and different than current buffer. + xp->xp_context = EXPAND_DIFF_BUFFERS; + xp->xp_pattern = arg; + break; +#endif + case CMD_USER: + case CMD_USER_BUF: + return set_context_in_user_cmdarg(cmd, arg, argt, compl, xp, + forceit); + + case CMD_map: case CMD_noremap: + case CMD_nmap: case CMD_nnoremap: + case CMD_vmap: case CMD_vnoremap: + case CMD_omap: case CMD_onoremap: + case CMD_imap: case CMD_inoremap: + case CMD_cmap: case CMD_cnoremap: + case CMD_lmap: case CMD_lnoremap: + case CMD_smap: case CMD_snoremap: + case CMD_tmap: case CMD_tnoremap: + case CMD_xmap: case CMD_xnoremap: + return set_context_in_map_cmd(xp, cmd, arg, forceit, + FALSE, FALSE, cmdidx); + case CMD_unmap: + case CMD_nunmap: + case CMD_vunmap: + case CMD_ounmap: + case CMD_iunmap: + case CMD_cunmap: + case CMD_lunmap: + case CMD_sunmap: + case CMD_tunmap: + case CMD_xunmap: + return set_context_in_map_cmd(xp, cmd, arg, forceit, + FALSE, TRUE, cmdidx); + case CMD_mapclear: + case CMD_nmapclear: + case CMD_vmapclear: + case CMD_omapclear: + case CMD_imapclear: + case CMD_cmapclear: + case CMD_lmapclear: + case CMD_smapclear: + case CMD_tmapclear: + case CMD_xmapclear: + xp->xp_context = EXPAND_MAPCLEAR; + xp->xp_pattern = arg; + break; + + case CMD_abbreviate: case CMD_noreabbrev: + case CMD_cabbrev: case CMD_cnoreabbrev: + case CMD_iabbrev: case CMD_inoreabbrev: + return set_context_in_map_cmd(xp, cmd, arg, forceit, + TRUE, FALSE, cmdidx); + case CMD_unabbreviate: + case CMD_cunabbrev: + case CMD_iunabbrev: + return set_context_in_map_cmd(xp, cmd, arg, forceit, + TRUE, TRUE, cmdidx); +#ifdef FEAT_MENU + case CMD_menu: case CMD_noremenu: case CMD_unmenu: + case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu: + case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu: + case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu: + case CMD_omenu: case CMD_onoremenu: case CMD_ounmenu: + case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu: + case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu: + case CMD_tlmenu: case CMD_tlnoremenu: case CMD_tlunmenu: + case CMD_tmenu: case CMD_tunmenu: + case CMD_popup: case CMD_tearoff: case CMD_emenu: + return set_context_in_menu_cmd(xp, cmd, arg, forceit); +#endif + + case CMD_colorscheme: + xp->xp_context = EXPAND_COLORS; + xp->xp_pattern = arg; + break; + + case CMD_compiler: + xp->xp_context = EXPAND_COMPILER; + xp->xp_pattern = arg; + break; + + case CMD_ownsyntax: + xp->xp_context = EXPAND_OWNSYNTAX; + xp->xp_pattern = arg; + break; + + case CMD_setfiletype: + xp->xp_context = EXPAND_FILETYPE; + xp->xp_pattern = arg; + break; + + case CMD_packadd: + xp->xp_context = EXPAND_PACKADD; + xp->xp_pattern = arg; + break; + + case CMD_runtime: + set_context_in_runtime_cmd(xp, arg); + break; + +#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) + case CMD_language: + return set_context_in_lang_cmd(xp, arg); +#endif +#if defined(FEAT_PROFILE) + case CMD_profile: + set_context_in_profile_cmd(xp, arg); + break; +#endif + case CMD_behave: + xp->xp_context = EXPAND_BEHAVE; + xp->xp_pattern = arg; + break; + + case CMD_messages: + xp->xp_context = EXPAND_MESSAGES; + xp->xp_pattern = arg; + break; + + case CMD_history: + xp->xp_context = EXPAND_HISTORY; + xp->xp_pattern = arg; + break; +#if defined(FEAT_PROFILE) + case CMD_syntime: + xp->xp_context = EXPAND_SYNTIME; + xp->xp_pattern = arg; + break; +#endif + + case CMD_argdelete: + while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) + arg = xp->xp_pattern + 1; + xp->xp_context = EXPAND_ARGLIST; + xp->xp_pattern = arg; + break; + +#ifdef FEAT_EVAL + case CMD_breakadd: + case CMD_profdel: + case CMD_breakdel: + return set_context_in_breakadd_cmd(xp, arg, cmdidx); + + case CMD_scriptnames: + return set_context_in_scriptnames_cmd(xp, arg); +#endif + + default: + break; + } + return NULL; +} + +/* + * This is all pretty much copied from do_one_cmd(), with all the extra stuff + * we don't need/want deleted. Maybe this could be done better if we didn't + * repeat all this stuff. The only problem is that they may not stay + * perfectly compatible with each other, but then the command line syntax + * probably won't change that much -- webb. + */ + static char_u * +set_one_cmd_context( + expand_T *xp, + char_u *buff) // buffer for command string +{ + char_u *p; + char_u *cmd, *arg; + int len = 0; + exarg_T ea; + int compl = EXPAND_NOTHING; + int forceit = FALSE; + int usefilter = FALSE; // filter instead of file name + + ExpandInit(xp); + xp->xp_pattern = buff; + xp->xp_line = buff; + xp->xp_context = EXPAND_COMMANDS; // Default until we get past command + ea.argt = 0; + + // 1. skip comment lines and leading space, colons or bars + for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++) + ; + xp->xp_pattern = cmd; + + if (*cmd == NUL) + return NULL; + if (*cmd == '"') // ignore comment lines + { + xp->xp_context = EXPAND_NOTHING; + return NULL; + } + + // 3. Skip over the range to find the command. + cmd = skip_range(cmd, TRUE, &xp->xp_context); + xp->xp_pattern = cmd; + if (*cmd == NUL) + return NULL; + if (*cmd == '"') + { + xp->xp_context = EXPAND_NOTHING; + return NULL; + } + + if (*cmd == '|' || *cmd == '\n') + return cmd + 1; // There's another command + + // Get the command index. + p = set_cmd_index(cmd, &ea, xp, &compl); + if (p == NULL) + return NULL; + + xp->xp_context = EXPAND_NOTHING; // Default now that we're past command + + if (*p == '!') // forced commands + { + forceit = TRUE; + ++p; + } + + // 6. parse arguments + if (!IS_USER_CMDIDX(ea.cmdidx)) + ea.argt = excmd_get_argt(ea.cmdidx); + + arg = skipwhite(p); + + // Skip over ++argopt argument + if ((ea.argt & EX_ARGOPT) && *arg != NUL && STRNCMP(arg, "++", 2) == 0) + { + p = arg; + while (*p && !vim_isspace(*p)) + MB_PTR_ADV(p); + arg = skipwhite(p); + } + + if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) + { + if (*arg == '>') // append + { + if (*++arg == '>') + ++arg; + arg = skipwhite(arg); + } + else if (*arg == '!' && ea.cmdidx == CMD_write) // :w !filter + { + ++arg; + usefilter = TRUE; + } + } + + if (ea.cmdidx == CMD_read) + { + usefilter = forceit; // :r! filter if forced + if (*arg == '!') // :r !filter + { + ++arg; + usefilter = TRUE; + } + } + + if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) + { + while (*arg == *cmd) // allow any number of '>' or '<' + ++arg; + arg = skipwhite(arg); + } + + // Does command allow "+command"? + if ((ea.argt & EX_CMDARG) && !usefilter && *arg == '+') + { + // Check if we're in the +command + p = arg + 1; + arg = skip_cmd_arg(arg, FALSE); + + // Still touching the command after '+'? + if (*arg == NUL) + return p; + + // Skip space(s) after +command to get to the real argument + arg = skipwhite(arg); + } + + + // Check for '|' to separate commands and '"' to start comments. + // Don't do this for ":read !cmd" and ":write !cmd". + if ((ea.argt & EX_TRLBAR) && !usefilter) + { + p = arg; + // ":redir @" is not the start of a comment + if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"') + p += 2; + while (*p) + { + if (*p == Ctrl_V) + { + if (p[1] != NUL) + ++p; + } + else if ( (*p == '"' && !(ea.argt & EX_NOTRLCOM)) + || *p == '|' || *p == '\n') + { + if (*(p - 1) != '\\') + { + if (*p == '|' || *p == '\n') + return p + 1; + return NULL; // It's a comment + } + } + MB_PTR_ADV(p); + } + } + + if (!(ea.argt & EX_EXTRA) && *arg != NUL + && vim_strchr((char_u *)"|\"", *arg) == NULL) + // no arguments allowed but there is something + return NULL; + + // Find start of last argument (argument just before cursor): + p = buff; + xp->xp_pattern = p; + len = (int)STRLEN(buff); + while (*p && p < buff + len) + { + if (*p == ' ' || *p == TAB) + { + // argument starts after a space + xp->xp_pattern = ++p; + } + else + { + if (*p == '\\' && *(p + 1) != NUL) + ++p; // skip over escaped character + MB_PTR_ADV(p); + } + } + + if (ea.argt & EX_XFILE) + set_context_for_wildcard_arg(&ea, arg, usefilter, xp, &compl); + + // 6. Switch on command name. + return set_context_by_cmdname(cmd, ea.cmdidx, xp, arg, ea.argt, compl, + forceit); +} + +/* + * Set the completion context in 'xp' for command 'str' + */ + void +set_cmd_context( + expand_T *xp, + char_u *str, // start of command line + int len, // length of command line (excl. NUL) + int col, // position of cursor + int use_ccline UNUSED) // use ccline for info +{ +#ifdef FEAT_EVAL + cmdline_info_T *ccline = get_cmdline_info(); +#endif + int old_char = NUL; + char_u *nextcomm; + + // Avoid a UMR warning from Purify, only save the character if it has been + // written before. + if (col < len) + old_char = str[col]; + str[col] = NUL; + nextcomm = str; + +#ifdef FEAT_EVAL + if (use_ccline && ccline->cmdfirstc == '=') + { + // pass CMD_SIZE because there is no real command + set_context_for_expression(xp, str, CMD_SIZE); + } + else if (use_ccline && ccline->input_fn) + { + xp->xp_context = ccline->xp_context; + xp->xp_pattern = ccline->cmdbuff; + xp->xp_arg = ccline->xp_arg; + } + else +#endif + while (nextcomm != NULL) + nextcomm = set_one_cmd_context(xp, nextcomm); + + // Store the string here so that call_user_expand_func() can get to them + // easily. + xp->xp_line = str; + xp->xp_col = col; + + str[col] = old_char; +} + +/* + * Expand the command line "str" from context "xp". + * "xp" must have been set by set_cmd_context(). + * xp->xp_pattern points into "str", to where the text that is to be expanded + * starts. + * Returns EXPAND_UNSUCCESSFUL when there is something illegal before the + * cursor. + * Returns EXPAND_NOTHING when there is nothing to expand, might insert the + * key that triggered expansion literally. + * Returns EXPAND_OK otherwise. + */ + int +expand_cmdline( + expand_T *xp, + char_u *str, // start of command line + int col, // position of cursor + int *matchcount, // return: nr of matches + char_u ***matches) // return: array of pointers to matches +{ + char_u *file_str = NULL; + int options = WILD_ADD_SLASH|WILD_SILENT; + + if (xp->xp_context == EXPAND_UNSUCCESSFUL) + { + beep_flush(); + return EXPAND_UNSUCCESSFUL; // Something illegal on command line + } + if (xp->xp_context == EXPAND_NOTHING) + { + // Caller can use the character as a normal char instead + return EXPAND_NOTHING; + } + + // add star to file name, or convert to regexp if not exp. files. + xp->xp_pattern_len = (int)(str + col - xp->xp_pattern); + if (cmdline_fuzzy_completion_supported(xp)) + // If fuzzy matching, don't modify the search string + file_str = vim_strsave(xp->xp_pattern); + else + { + file_str = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); + if (file_str == NULL) + return EXPAND_UNSUCCESSFUL; + } + + if (p_wic) + options += WILD_ICASE; + + // find all files that match the description + if (ExpandFromContext(xp, file_str, matches, matchcount, options) == FAIL) + { + *matchcount = 0; + *matches = NULL; + } + vim_free(file_str); + + return EXPAND_OK; +} + +/* + * Expand file or directory names. + * Returns OK or FAIL. + */ + static int +expand_files_and_dirs( + expand_T *xp, + char_u *pat, + char_u ***matches, + int *numMatches, + int flags, + int options) +{ + int free_pat = FALSE; + int i; + int ret; + + // for ":set path=" and ":set tags=" halve backslashes for escaped + // space + if (xp->xp_backslash != XP_BS_NONE) + { + free_pat = TRUE; + pat = vim_strsave(pat); + for (i = 0; pat[i]; ++i) + if (pat[i] == '\\') + { + if (xp->xp_backslash == XP_BS_THREE + && pat[i + 1] == '\\' + && pat[i + 2] == '\\' + && pat[i + 3] == ' ') + STRMOVE(pat + i, pat + i + 3); + if (xp->xp_backslash == XP_BS_ONE + && pat[i + 1] == ' ') + STRMOVE(pat + i, pat + i + 1); + } + } + + if (xp->xp_context == EXPAND_FILES) + flags |= EW_FILE; + else if (xp->xp_context == EXPAND_FILES_IN_PATH) + flags |= (EW_FILE | EW_PATH); + else + flags = (flags | EW_DIR) & ~EW_FILE; + if (options & WILD_ICASE) + flags |= EW_ICASE; + + // Expand wildcards, supporting %:h and the like. + ret = expand_wildcards_eval(&pat, numMatches, matches, flags); + if (free_pat) + vim_free(pat); +#ifdef BACKSLASH_IN_FILENAME + if (p_csl[0] != NUL && (options & WILD_IGNORE_COMPLETESLASH) == 0) + { + int j; + + for (j = 0; j < *numMatches; ++j) + { + char_u *ptr = (*matches)[j]; + + while (*ptr != NUL) + { + if (p_csl[0] == 's' && *ptr == '\\') + *ptr = '/'; + else if (p_csl[0] == 'b' && *ptr == '/') + *ptr = '\\'; + ptr += (*mb_ptr2len)(ptr); + } + } + } +#endif + return ret; +} + +/* + * Function given to ExpandGeneric() to obtain the possible arguments of the + * ":behave {mswin,xterm}" command. + */ + static char_u * +get_behave_arg(expand_T *xp UNUSED, int idx) +{ + if (idx == 0) + return (char_u *)"mswin"; + if (idx == 1) + return (char_u *)"xterm"; + return NULL; +} + +#ifdef FEAT_EVAL +/* + * Function given to ExpandGeneric() to obtain the possible arguments of the + * ":breakadd {expr, file, func, here}" command. + * ":breakdel {func, file, here}" command. + */ + static char_u * +get_breakadd_arg(expand_T *xp UNUSED, int idx) +{ + char *opts[] = {"expr", "file", "func", "here"}; + + if (idx >= 0 && idx <= 3) + { + // breakadd {expr, file, func, here} + if (breakpt_expand_what == EXP_BREAKPT_ADD) + return (char_u *)opts[idx]; + else if (breakpt_expand_what == EXP_BREAKPT_DEL) + { + // breakdel {func, file, here} + if (idx <= 2) + return (char_u *)opts[idx + 1]; + } + else + { + // profdel {func, file} + if (idx <= 1) + return (char_u *)opts[idx + 1]; + } + } + return NULL; +} + +/* + * Function given to ExpandGeneric() to obtain the possible arguments for the + * ":scriptnames" command. + */ + static char_u * +get_scriptnames_arg(expand_T *xp UNUSED, int idx) +{ + scriptitem_T *si; + + if (!SCRIPT_ID_VALID(idx + 1)) + return NULL; + + si = SCRIPT_ITEM(idx + 1); + home_replace(NULL, si->sn_name, NameBuff, MAXPATHL, TRUE); + return NameBuff; +} +#endif + +/* + * Function given to ExpandGeneric() to obtain the possible arguments of the + * ":messages {clear}" command. + */ + static char_u * +get_messages_arg(expand_T *xp UNUSED, int idx) +{ + if (idx == 0) + return (char_u *)"clear"; + return NULL; +} + + static char_u * +get_mapclear_arg(expand_T *xp UNUSED, int idx) +{ + if (idx == 0) + return (char_u *)""; + return NULL; +} + +/* + * Do the expansion based on xp->xp_context and 'rmp'. + */ + static int +ExpandOther( + char_u *pat, + expand_T *xp, + regmatch_T *rmp, + char_u ***matches, + int *numMatches) +{ + static struct expgen + { + int context; + char_u *((*func)(expand_T *, int)); + int ic; + int escaped; + } tab[] = + { + {EXPAND_COMMANDS, get_command_name, FALSE, TRUE}, + {EXPAND_BEHAVE, get_behave_arg, TRUE, TRUE}, + {EXPAND_MAPCLEAR, get_mapclear_arg, TRUE, TRUE}, + {EXPAND_MESSAGES, get_messages_arg, TRUE, TRUE}, + {EXPAND_HISTORY, get_history_arg, TRUE, TRUE}, + {EXPAND_USER_COMMANDS, get_user_commands, FALSE, TRUE}, + {EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, FALSE, TRUE}, + {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE}, + {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE}, + {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE}, +#ifdef FEAT_EVAL + {EXPAND_USER_VARS, get_user_var_name, FALSE, TRUE}, + {EXPAND_FUNCTIONS, get_function_name, FALSE, TRUE}, + {EXPAND_USER_FUNC, get_user_func_name, FALSE, TRUE}, + {EXPAND_DISASSEMBLE, get_disassemble_argument, FALSE, TRUE}, + {EXPAND_EXPRESSION, get_expr_name, FALSE, TRUE}, +#endif +#ifdef FEAT_MENU + {EXPAND_MENUS, get_menu_name, FALSE, TRUE}, + {EXPAND_MENUNAMES, get_menu_names, FALSE, TRUE}, +#endif +#ifdef FEAT_SYN_HL + {EXPAND_SYNTAX, get_syntax_name, TRUE, TRUE}, +#endif +#ifdef FEAT_PROFILE + {EXPAND_SYNTIME, get_syntime_arg, TRUE, TRUE}, +#endif + {EXPAND_HIGHLIGHT, get_highlight_name, TRUE, TRUE}, + {EXPAND_EVENTS, get_event_name, TRUE, FALSE}, + {EXPAND_AUGROUP, get_augroup_name, TRUE, FALSE}, +#ifdef FEAT_CSCOPE + {EXPAND_CSCOPE, get_cscope_name, TRUE, TRUE}, +#endif +#ifdef FEAT_SIGNS + {EXPAND_SIGN, get_sign_name, TRUE, TRUE}, +#endif +#ifdef FEAT_PROFILE + {EXPAND_PROFILE, get_profile_name, TRUE, TRUE}, +#endif +#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) + {EXPAND_LANGUAGE, get_lang_arg, TRUE, FALSE}, + {EXPAND_LOCALES, get_locales, TRUE, FALSE}, +#endif + {EXPAND_ENV_VARS, get_env_name, TRUE, TRUE}, + {EXPAND_USER, get_users, TRUE, FALSE}, + {EXPAND_ARGLIST, get_arglist_name, TRUE, FALSE}, +#ifdef FEAT_EVAL + {EXPAND_BREAKPOINT, get_breakadd_arg, TRUE, TRUE}, + {EXPAND_SCRIPTNAMES, get_scriptnames_arg, TRUE, FALSE}, +#endif + }; + int i; + int ret = FAIL; + + // Find a context in the table and call the ExpandGeneric() with the + // right function to do the expansion. + for (i = 0; i < (int)ARRAY_LENGTH(tab); ++i) + { + if (xp->xp_context == tab[i].context) + { + if (tab[i].ic) + rmp->rm_ic = TRUE; + ret = ExpandGeneric(pat, xp, rmp, matches, numMatches, + tab[i].func, tab[i].escaped); + break; + } + } + + return ret; +} + +/* + * Map wild expand options to flags for expand_wildcards() + */ + static int +map_wildopts_to_ewflags(int options) +{ + int flags; + + flags = EW_DIR; // include directories + if (options & WILD_LIST_NOTFOUND) + flags |= EW_NOTFOUND; + if (options & WILD_ADD_SLASH) + flags |= EW_ADDSLASH; + if (options & WILD_KEEP_ALL) + flags |= EW_KEEPALL; + if (options & WILD_SILENT) + flags |= EW_SILENT; + if (options & WILD_NOERROR) + flags |= EW_NOERROR; + if (options & WILD_ALLLINKS) + flags |= EW_ALLLINKS; + + return flags; +} + +/* + * Do the expansion based on xp->xp_context and "pat". + */ + static int +ExpandFromContext( + expand_T *xp, + char_u *pat, + char_u ***matches, + int *numMatches, + int options) // WILD_ flags +{ + regmatch_T regmatch; + int ret; + int flags; + char_u *tofree = NULL; + int fuzzy = cmdline_fuzzy_complete(pat) + && cmdline_fuzzy_completion_supported(xp); + + flags = map_wildopts_to_ewflags(options); + + if (xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_DIRECTORIES + || xp->xp_context == EXPAND_FILES_IN_PATH) + return expand_files_and_dirs(xp, pat, matches, numMatches, flags, + options); + + *matches = (char_u **)""; + *numMatches = 0; + if (xp->xp_context == EXPAND_HELP) + { + // With an empty argument we would get all the help tags, which is + // very slow. Get matches for "help" instead. + if (find_help_tags(*pat == NUL ? (char_u *)"help" : pat, + numMatches, matches, FALSE) == OK) + { +#ifdef FEAT_MULTI_LANG + cleanup_help_tags(*numMatches, *matches); +#endif + return OK; + } + return FAIL; + } + + if (xp->xp_context == EXPAND_SHELLCMD) + return expand_shellcmd(pat, matches, numMatches, flags); + if (xp->xp_context == EXPAND_OLD_SETTING) + return ExpandOldSetting(numMatches, matches); + if (xp->xp_context == EXPAND_BUFFERS) + return ExpandBufnames(pat, numMatches, matches, options); +#ifdef FEAT_DIFF + if (xp->xp_context == EXPAND_DIFF_BUFFERS) + return ExpandBufnames(pat, numMatches, matches, + options | BUF_DIFF_FILTER); +#endif + if (xp->xp_context == EXPAND_TAGS + || xp->xp_context == EXPAND_TAGS_LISTFILES) + return expand_tags(xp->xp_context == EXPAND_TAGS, pat, numMatches, + matches); + if (xp->xp_context == EXPAND_COLORS) + { + char *directories[] = {"colors", NULL}; + return ExpandRTDir(pat, DIP_START + DIP_OPT, numMatches, matches, + directories); + } + if (xp->xp_context == EXPAND_COMPILER) + { + char *directories[] = {"compiler", NULL}; + return ExpandRTDir(pat, 0, numMatches, matches, directories); + } + if (xp->xp_context == EXPAND_OWNSYNTAX) + { + char *directories[] = {"syntax", NULL}; + return ExpandRTDir(pat, 0, numMatches, matches, directories); + } + if (xp->xp_context == EXPAND_FILETYPE) + { + char *directories[] = {"syntax", "indent", "ftplugin", NULL}; + return ExpandRTDir(pat, 0, numMatches, matches, directories); + } +#if defined(FEAT_EVAL) + if (xp->xp_context == EXPAND_USER_LIST) + return ExpandUserList(xp, matches, numMatches); +#endif + if (xp->xp_context == EXPAND_PACKADD) + return ExpandPackAddDir(pat, numMatches, matches); + if (xp->xp_context == EXPAND_RUNTIME) + return expand_runtime_cmd(pat, numMatches, matches); + + // When expanding a function name starting with s:, match the nr_ + // prefix. + if ((xp->xp_context == EXPAND_USER_FUNC + || xp->xp_context == EXPAND_DISASSEMBLE) + && STRNCMP(pat, "^s:", 3) == 0) + { + int len = (int)STRLEN(pat) + 20; + + tofree = alloc(len); + if (tofree == NULL) + return FAIL; + vim_snprintf((char *)tofree, len, "^\\d\\+_%s", pat + 3); + pat = tofree; + } + + if (!fuzzy) + { + regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0); + if (regmatch.regprog == NULL) + return FAIL; + + // set ignore-case according to p_ic, p_scs and pat + regmatch.rm_ic = ignorecase(pat); + } + + if (xp->xp_context == EXPAND_SETTINGS + || xp->xp_context == EXPAND_BOOL_SETTINGS) + ret = ExpandSettings(xp, ®match, pat, numMatches, matches, fuzzy); + else if (xp->xp_context == EXPAND_MAPPINGS) + ret = ExpandMappings(pat, ®match, numMatches, matches); +#if defined(FEAT_EVAL) + else if (xp->xp_context == EXPAND_USER_DEFINED) + ret = ExpandUserDefined(pat, xp, ®match, matches, numMatches); +#endif + else + ret = ExpandOther(pat, xp, ®match, matches, numMatches); + + if (!fuzzy) + vim_regfree(regmatch.regprog); + vim_free(tofree); + + return ret; +} + +/* + * Expand a list of names. + * + * Generic function for command line completion. It calls a function to + * obtain strings, one by one. The strings are matched against a regexp + * program. Matching strings are copied into an array, which is returned. + * + * If 'fuzzy' is TRUE, then fuzzy matching is used. Otherwise, regex matching + * is used. + * + * Returns OK when no problems encountered, FAIL for error (out of memory). + */ + static int +ExpandGeneric( + char_u *pat, + expand_T *xp, + regmatch_T *regmatch, + char_u ***matches, + int *numMatches, + char_u *((*func)(expand_T *, int)), + // returns a string from the list + int escaped) +{ + int i; + garray_T ga; + char_u *str; + fuzmatch_str_T *fuzmatch = NULL; + int score = 0; + int fuzzy; + int match; + int sort_matches = FALSE; + int funcsort = FALSE; + + fuzzy = cmdline_fuzzy_complete(pat); + *matches = NULL; + *numMatches = 0; + + if (!fuzzy) + ga_init2(&ga, sizeof(char *), 30); + else + ga_init2(&ga, sizeof(fuzmatch_str_T), 30); + + for (i = 0; ; ++i) + { + str = (*func)(xp, i); + if (str == NULL) // end of list + break; + if (*str == NUL) // skip empty strings + continue; + + if (xp->xp_pattern[0] != NUL) + { + if (!fuzzy) + match = vim_regexec(regmatch, str, (colnr_T)0); + else + { + score = fuzzy_match_str(str, pat); + match = (score != 0); + } + } + else + match = TRUE; + + if (!match) + continue; + + if (escaped) + str = vim_strsave_escaped(str, (char_u *)" \t\\."); + else + str = vim_strsave(str); + if (str == NULL) + { + if (!fuzzy) + { + ga_clear_strings(&ga); + return FAIL; + } + fuzmatch_str_free(ga.ga_data, ga.ga_len); + return FAIL; + } + + if (ga_grow(&ga, 1) == FAIL) + { + vim_free(str); + break; + } + + if (fuzzy) + { + fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len]; + fuzmatch->idx = ga.ga_len; + fuzmatch->str = str; + fuzmatch->score = score; + } + else + ((char_u **)ga.ga_data)[ga.ga_len] = str; + +#ifdef FEAT_MENU + if (func == get_menu_names) + { + // test for separator added by get_menu_names() + str += STRLEN(str) - 1; + if (*str == '\001') + *str = '.'; + } +#endif + + ++ga.ga_len; + } + + if (ga.ga_len == 0) + return OK; + + // sort the matches when using regular expression matching and sorting + // applies to the completion context. Menus and scriptnames should be kept + // in the specified order. + if (!fuzzy && xp->xp_context != EXPAND_MENUNAMES + && xp->xp_context != EXPAND_MENUS + && xp->xp_context != EXPAND_SCRIPTNAMES) + sort_matches = TRUE; + + // functions should be sorted to the end. + if (xp->xp_context == EXPAND_EXPRESSION + || xp->xp_context == EXPAND_FUNCTIONS + || xp->xp_context == EXPAND_USER_FUNC + || xp->xp_context == EXPAND_DISASSEMBLE) + funcsort = TRUE; + + // Sort the matches. + if (sort_matches) + { + if (funcsort) + // functions should be sorted to the end. + qsort((void *)ga.ga_data, (size_t)ga.ga_len, sizeof(char_u *), + sort_func_compare); + else + sort_strings((char_u **)ga.ga_data, ga.ga_len); + } + + if (!fuzzy) + { + *matches = ga.ga_data; + *numMatches = ga.ga_len; + } + else + { + if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len, + funcsort) == FAIL) + return FAIL; + *numMatches = ga.ga_len; + } + +#if defined(FEAT_SYN_HL) + // Reset the variables used for special highlight names expansion, so that + // they don't show up when getting normal highlight names by ID. + reset_expand_highlight(); +#endif + + return OK; +} + +/* + * Expand shell command matches in one directory of $PATH. + */ + static void +expand_shellcmd_onedir( + char_u *buf, + char_u *s, + size_t l, + char_u *pat, + char_u ***matches, + int *numMatches, + int flags, + hashtab_T *ht, + garray_T *gap) +{ + int ret; + hash_T hash; + hashitem_T *hi; + + vim_strncpy(buf, s, l); + add_pathsep(buf); + l = STRLEN(buf); + vim_strncpy(buf + l, pat, MAXPATHL - 1 - l); + + // Expand matches in one directory of $PATH. + ret = expand_wildcards(1, &buf, numMatches, matches, flags); + if (ret != OK) + return; + + if (ga_grow(gap, *numMatches) == FAIL) + { + FreeWild(*numMatches, *matches); + return; + } + + for (int i = 0; i < *numMatches; ++i) + { + char_u *name = (*matches)[i]; + + if (STRLEN(name) > l) + { + // Check if this name was already found. + hash = hash_hash(name + l); + hi = hash_lookup(ht, name + l, hash); + if (HASHITEM_EMPTY(hi)) + { + // Remove the path that was prepended. + STRMOVE(name, name + l); + ((char_u **)gap->ga_data)[gap->ga_len++] = name; + hash_add_item(ht, hi, name, hash); + name = NULL; + } + } + vim_free(name); + } + vim_free(*matches); +} + +/* + * Complete a shell command. + * Returns FAIL or OK; + */ + static int +expand_shellcmd( + char_u *filepat, // pattern to match with command names + char_u ***matches, // return: array with matches + int *numMatches, // return: number of matches + int flagsarg) // EW_ flags +{ + char_u *pat; + int i; + char_u *path = NULL; + int mustfree = FALSE; + garray_T ga; + char_u *buf; + size_t l; + char_u *s, *e; + int flags = flagsarg; + int did_curdir = FALSE; + hashtab_T found_ht; + + buf = alloc(MAXPATHL); + if (buf == NULL) + return FAIL; + + // for ":set path=" and ":set tags=" halve backslashes for escaped space + pat = vim_strsave(filepat); + if (pat == NULL) + { + vim_free(buf); + return FAIL; + } + + for (i = 0; pat[i]; ++i) + if (pat[i] == '\\' && pat[i + 1] == ' ') + STRMOVE(pat + i, pat + i + 1); + + flags |= EW_FILE | EW_EXEC | EW_SHELLCMD; + + if (pat[0] == '.' && (vim_ispathsep(pat[1]) + || (pat[1] == '.' && vim_ispathsep(pat[2])))) + path = (char_u *)"."; + else + { + // For an absolute name we don't use $PATH. + if (!mch_isFullName(pat)) + path = vim_getenv((char_u *)"PATH", &mustfree); + if (path == NULL) + path = (char_u *)""; + } + + // Go over all directories in $PATH. Expand matches in that directory and + // collect them in "ga". When "." is not in $PATH also expand for the + // current directory, to find "subdir/cmd". + ga_init2(&ga, sizeof(char *), 10); + hash_init(&found_ht); + for (s = path; ; s = e) + { +#if defined(MSWIN) + e = vim_strchr(s, ';'); +#else + e = vim_strchr(s, ':'); +#endif + if (e == NULL) + e = s + STRLEN(s); + + if (*s == NUL) + { + if (did_curdir) + break; + // Find directories in the current directory, path is empty. + did_curdir = TRUE; + flags |= EW_DIR; + } + else if (STRNCMP(s, ".", (int)(e - s)) == 0) + { + did_curdir = TRUE; + flags |= EW_DIR; + } + else + // Do not match directories inside a $PATH item. + flags &= ~EW_DIR; + + l = e - s; + if (l > MAXPATHL - 5) + break; + + expand_shellcmd_onedir(buf, s, l, pat, matches, numMatches, flags, + &found_ht, &ga); + + if (*e != NUL) + ++e; + } + *matches = ga.ga_data; + *numMatches = ga.ga_len; + + vim_free(buf); + vim_free(pat); + if (mustfree) + vim_free(path); + hash_clear(&found_ht); + return OK; +} + +#if defined(FEAT_EVAL) +/* + * Call "user_expand_func()" to invoke a user defined Vim script function and + * return the result (either a string, a List or NULL). + */ + static void * +call_user_expand_func( + void *(*user_expand_func)(char_u *, int, typval_T *), + expand_T *xp) +{ + cmdline_info_T *ccline = get_cmdline_info(); + int keep = 0; + typval_T args[4]; + sctx_T save_current_sctx = current_sctx; + char_u *pat = NULL; + void *ret; + + if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) + return NULL; + + if (ccline->cmdbuff != NULL) + { + keep = ccline->cmdbuff[ccline->cmdlen]; + ccline->cmdbuff[ccline->cmdlen] = 0; + } + + pat = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len); + + args[0].v_type = VAR_STRING; + args[0].vval.v_string = pat; + args[1].v_type = VAR_STRING; + args[1].vval.v_string = xp->xp_line; + args[2].v_type = VAR_NUMBER; + args[2].vval.v_number = xp->xp_col; + args[3].v_type = VAR_UNKNOWN; + + current_sctx = xp->xp_script_ctx; + + ret = user_expand_func(xp->xp_arg, 3, args); + + current_sctx = save_current_sctx; + if (ccline->cmdbuff != NULL) + ccline->cmdbuff[ccline->cmdlen] = keep; + + vim_free(pat); + return ret; +} + +/* + * Expand names with a function defined by the user (EXPAND_USER_DEFINED and + * EXPAND_USER_LIST). + */ + static int +ExpandUserDefined( + char_u *pat, + expand_T *xp, + regmatch_T *regmatch, + char_u ***matches, + int *numMatches) +{ + char_u *retstr; + char_u *s; + char_u *e; + int keep; + garray_T ga; + int fuzzy; + int match; + int score = 0; + + fuzzy = cmdline_fuzzy_complete(pat); + *matches = NULL; + *numMatches = 0; + + retstr = call_user_expand_func(call_func_retstr, xp); + if (retstr == NULL) + return FAIL; + + if (!fuzzy) + ga_init2(&ga, sizeof(char *), 3); + else + ga_init2(&ga, sizeof(fuzmatch_str_T), 3); + + for (s = retstr; *s != NUL; s = e) + { + e = vim_strchr(s, '\n'); + if (e == NULL) + e = s + STRLEN(s); + keep = *e; + *e = NUL; + + if (xp->xp_pattern[0] != NUL) + { + if (!fuzzy) + match = vim_regexec(regmatch, s, (colnr_T)0); + else + { + score = fuzzy_match_str(s, pat); + match = (score != 0); + } + } + else + match = TRUE; // match everything + + *e = keep; + + if (match) + { + if (ga_grow(&ga, 1) == FAIL) + break; + if (!fuzzy) + ((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(s, e - s); + else + { + fuzmatch_str_T *fuzmatch = + &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len]; + fuzmatch->idx = ga.ga_len; + fuzmatch->str = vim_strnsave(s, e - s); + fuzmatch->score = score; + } + ++ga.ga_len; + } + + if (*e != NUL) + ++e; + } + vim_free(retstr); + + if (ga.ga_len == 0) + return OK; + + if (!fuzzy) + { + *matches = ga.ga_data; + *numMatches = ga.ga_len; + } + else + { + if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len, + FALSE) == FAIL) + return FAIL; + *numMatches = ga.ga_len; + } + return OK; +} + +/* + * Expand names with a list returned by a function defined by the user. + */ + static int +ExpandUserList( + expand_T *xp, + char_u ***matches, + int *numMatches) +{ + list_T *retlist; + listitem_T *li; + garray_T ga; + + *matches = NULL; + *numMatches = 0; + retlist = call_user_expand_func(call_func_retlist, xp); + if (retlist == NULL) + return FAIL; + + ga_init2(&ga, sizeof(char *), 3); + // Loop over the items in the list. + FOR_ALL_LIST_ITEMS(retlist, li) + { + if (li->li_tv.v_type != VAR_STRING || li->li_tv.vval.v_string == NULL) + continue; // Skip non-string items and empty strings + + if (ga_grow(&ga, 1) == FAIL) + break; + + ((char_u **)ga.ga_data)[ga.ga_len] = + vim_strsave(li->li_tv.vval.v_string); + ++ga.ga_len; + } + list_unref(retlist); + + *matches = ga.ga_data; + *numMatches = ga.ga_len; + return OK; +} +#endif + +/* + * Expand "file" for all comma-separated directories in "path". + * Adds the matches to "ga". Caller must init "ga". + * If "dirs" is TRUE only expand directory names. + */ + void +globpath( + char_u *path, + char_u *file, + garray_T *ga, + int expand_options, + int dirs) +{ + expand_T xpc; + char_u *buf; + int i; + int num_p; + char_u **p; + + buf = alloc(MAXPATHL); + if (buf == NULL) + return; + + ExpandInit(&xpc); + xpc.xp_context = dirs ? EXPAND_DIRECTORIES : EXPAND_FILES; + + // Loop over all entries in {path}. + while (*path != NUL) + { + // Copy one item of the path to buf[] and concatenate the file name. + copy_option_part(&path, buf, MAXPATHL, ","); + if (STRLEN(buf) + STRLEN(file) + 2 < MAXPATHL) + { +#if defined(MSWIN) + // Using the platform's path separator (\) makes vim incorrectly + // treat it as an escape character, use '/' instead. + if (*buf != NUL && !after_pathsep(buf, buf + STRLEN(buf))) + STRCAT(buf, "/"); +#else + add_pathsep(buf); +#endif + STRCAT(buf, file); + if (ExpandFromContext(&xpc, buf, &p, &num_p, + WILD_SILENT|expand_options) != FAIL && num_p > 0) + { + ExpandEscape(&xpc, buf, num_p, p, WILD_SILENT|expand_options); + + if (ga_grow(ga, num_p) == OK) + // take over the pointers and put them in "ga" + for (i = 0; i < num_p; ++i) + { + ((char_u **)ga->ga_data)[ga->ga_len] = p[i]; + ++ga->ga_len; + } + vim_free(p); + } + } + } + + vim_free(buf); +} + +/* + * Translate some keys pressed when 'wildmenu' is used. + */ + int +wildmenu_translate_key( + cmdline_info_T *cclp, + int key, + expand_T *xp, + int did_wild_list) +{ + int c = key; + + if (cmdline_pum_active()) + { + // When the popup menu is used for cmdline completion: + // Up : go to the previous item in the menu + // Down : go to the next item in the menu + // Left : go to the parent directory + // Right: list the files in the selected directory + switch (c) + { + case K_UP: c = K_LEFT; break; + case K_DOWN: c = K_RIGHT; break; + case K_LEFT: c = K_UP; break; + case K_RIGHT: c = K_DOWN; break; + default: break; + } + } + + if (did_wild_list) + { + if (c == K_LEFT) + c = Ctrl_P; + else if (c == K_RIGHT) + c = Ctrl_N; + } + + // Hitting CR after "emenu Name.": complete submenu + if (xp->xp_context == EXPAND_MENUNAMES + && cclp->cmdpos > 1 + && cclp->cmdbuff[cclp->cmdpos - 1] == '.' + && cclp->cmdbuff[cclp->cmdpos - 2] != '\\' + && (c == '\n' || c == '\r' || c == K_KENTER)) + c = K_DOWN; + + return c; +} + +/* + * Delete characters on the command line, from "from" to the current + * position. + */ + static void +cmdline_del(cmdline_info_T *cclp, int from) +{ + mch_memmove(cclp->cmdbuff + from, cclp->cmdbuff + cclp->cmdpos, + (size_t)(cclp->cmdlen - cclp->cmdpos + 1)); + cclp->cmdlen -= cclp->cmdpos - from; + cclp->cmdpos = from; +} + +/* + * Handle a key pressed when the wild menu for the menu names + * (EXPAND_MENUNAMES) is displayed. + */ + static int +wildmenu_process_key_menunames(cmdline_info_T *cclp, int key, expand_T *xp) +{ + int i; + int j; + + // Hitting after "emenu Name.": complete submenu + if (key == K_DOWN && cclp->cmdpos > 0 + && cclp->cmdbuff[cclp->cmdpos - 1] == '.') + { + key = p_wc; + KeyTyped = TRUE; // in case the key was mapped + } + else if (key == K_UP) + { + // Hitting : Remove one submenu name in front of the + // cursor + int found = FALSE; + + j = (int)(xp->xp_pattern - cclp->cmdbuff); + i = 0; + while (--j > 0) + { + // check for start of menu name + if (cclp->cmdbuff[j] == ' ' + && cclp->cmdbuff[j - 1] != '\\') + { + i = j + 1; + break; + } + // check for start of submenu name + if (cclp->cmdbuff[j] == '.' + && cclp->cmdbuff[j - 1] != '\\') + { + if (found) + { + i = j + 1; + break; + } + else + found = TRUE; + } + } + if (i > 0) + cmdline_del(cclp, i); + key = p_wc; + KeyTyped = TRUE; // in case the key was mapped + xp->xp_context = EXPAND_NOTHING; + } + + return key; +} + +/* + * Handle a key pressed when the wild menu for file names (EXPAND_FILES) or + * directory names (EXPAND_DIRECTORIES) or shell command names + * (EXPAND_SHELLCMD) is displayed. + */ + static int +wildmenu_process_key_filenames(cmdline_info_T *cclp, int key, expand_T *xp) +{ + int i; + int j; + char_u upseg[5]; + + upseg[0] = PATHSEP; + upseg[1] = '.'; + upseg[2] = '.'; + upseg[3] = PATHSEP; + upseg[4] = NUL; + + if (key == K_DOWN + && cclp->cmdpos > 0 + && cclp->cmdbuff[cclp->cmdpos - 1] == PATHSEP + && (cclp->cmdpos < 3 + || cclp->cmdbuff[cclp->cmdpos - 2] != '.' + || cclp->cmdbuff[cclp->cmdpos - 3] != '.')) + { + // go down a directory + key = p_wc; + KeyTyped = TRUE; // in case the key was mapped + } + else if (STRNCMP(xp->xp_pattern, upseg + 1, 3) == 0 && key == K_DOWN) + { + // If in a direct ancestor, strip off one ../ to go down + int found = FALSE; + + j = cclp->cmdpos; + i = (int)(xp->xp_pattern - cclp->cmdbuff); + while (--j > i) + { + if (has_mbyte) + j -= (*mb_head_off)(cclp->cmdbuff, cclp->cmdbuff + j); + if (vim_ispathsep(cclp->cmdbuff[j])) + { + found = TRUE; + break; + } + } + if (found + && cclp->cmdbuff[j - 1] == '.' + && cclp->cmdbuff[j - 2] == '.' + && (vim_ispathsep(cclp->cmdbuff[j - 3]) || j == i + 2)) + { + cmdline_del(cclp, j - 2); + key = p_wc; + KeyTyped = TRUE; // in case the key was mapped + } + } + else if (key == K_UP) + { + // go up a directory + int found = FALSE; + + j = cclp->cmdpos - 1; + i = (int)(xp->xp_pattern - cclp->cmdbuff); + while (--j > i) + { + if (has_mbyte) + j -= (*mb_head_off)(cclp->cmdbuff, cclp->cmdbuff + j); + if (vim_ispathsep(cclp->cmdbuff[j]) +#ifdef BACKSLASH_IN_FILENAME + && vim_strchr((char_u *)" *?[{`$%#", + cclp->cmdbuff[j + 1]) == NULL +#endif + ) + { + if (found) + { + i = j + 1; + break; + } + else + found = TRUE; + } + } + + if (!found) + j = i; + else if (STRNCMP(cclp->cmdbuff + j, upseg, 4) == 0) + j += 4; + else if (STRNCMP(cclp->cmdbuff + j, upseg + 1, 3) == 0 + && j == i) + j += 3; + else + j = 0; + if (j > 0) + { + // TODO this is only for DOS/UNIX systems - need to put in + // machine-specific stuff here and in upseg init + cmdline_del(cclp, j); + put_on_cmdline(upseg + 1, 3, FALSE); + } + else if (cclp->cmdpos > i) + cmdline_del(cclp, i); + + // Now complete in the new directory. Set KeyTyped in case the + // Up key came from a mapping. + key = p_wc; + KeyTyped = TRUE; + } + + return key; +} + +/* + * Handle a key pressed when the wild menu is displayed + */ + int +wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp) +{ + if (xp->xp_context == EXPAND_MENUNAMES) + return wildmenu_process_key_menunames(cclp, key, xp); + else if ((xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_DIRECTORIES + || xp->xp_context == EXPAND_SHELLCMD)) + return wildmenu_process_key_filenames(cclp, key, xp); + + return key; +} + +/* + * Free expanded names when finished walking through the matches + */ + void +wildmenu_cleanup(cmdline_info_T *cclp UNUSED) +{ + int skt = KeyTyped; +#ifdef FEAT_EVAL + int old_RedrawingDisabled = RedrawingDisabled; +#endif + + if (!p_wmnu || wild_menu_showing == 0) + return; + +#ifdef FEAT_EVAL + if (cclp->input_fn) + RedrawingDisabled = 0; +#endif + + if (wild_menu_showing == WM_SCROLLED) + { + // Entered command line, move it up + cmdline_row--; + redrawcmd(); + } + else if (save_p_ls != -1) + { + // restore 'laststatus' and 'winminheight' + p_ls = save_p_ls; + p_wmh = save_p_wmh; + last_status(FALSE); + update_screen(UPD_VALID); // redraw the screen NOW + redrawcmd(); + save_p_ls = -1; + } + else + { + win_redraw_last_status(topframe); + redraw_statuslines(); + } + KeyTyped = skt; + wild_menu_showing = 0; +#ifdef FEAT_EVAL + if (cclp->input_fn) + RedrawingDisabled = old_RedrawingDisabled; +#endif +} + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * "getcompletion()" function + */ + void +f_getcompletion(typval_T *argvars, typval_T *rettv) +{ + char_u *pat; + char_u *type; + expand_T xpc; + int filtered = FALSE; + int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH + | WILD_NO_BEEP | WILD_HOME_REPLACE; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL + || check_for_opt_bool_arg(argvars, 2) == FAIL)) + return; + + pat = tv_get_string(&argvars[0]); + if (check_for_string_arg(argvars, 1) == FAIL) + return; + type = tv_get_string(&argvars[1]); + + if (argvars[2].v_type != VAR_UNKNOWN) + filtered = tv_get_bool_chk(&argvars[2], NULL); + + if (p_wic) + options |= WILD_ICASE; + + // For filtered results, 'wildignore' is used + if (!filtered) + options |= WILD_KEEP_ALL; + + ExpandInit(&xpc); + if (STRCMP(type, "cmdline") == 0) + { + set_one_cmd_context(&xpc, pat); + xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); + xpc.xp_col = (int)STRLEN(pat); + } + else + { + xpc.xp_pattern = pat; + xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); + + xpc.xp_context = cmdcomplete_str_to_type(type); + if (xpc.xp_context == EXPAND_NOTHING) + { + semsg(_(e_invalid_argument_str), type); + return; + } + +# if defined(FEAT_MENU) + if (xpc.xp_context == EXPAND_MENUS) + { + set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE); + xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); + } +# endif +# ifdef FEAT_CSCOPE + if (xpc.xp_context == EXPAND_CSCOPE) + { + set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope); + xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); + } +# endif +# ifdef FEAT_SIGNS + if (xpc.xp_context == EXPAND_SIGN) + { + set_context_in_sign_cmd(&xpc, xpc.xp_pattern); + xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); + } +# endif + if (xpc.xp_context == EXPAND_RUNTIME) + { + set_context_in_runtime_cmd(&xpc, xpc.xp_pattern); + xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); + } + } + + if (cmdline_fuzzy_completion_supported(&xpc)) + // when fuzzy matching, don't modify the search string + pat = vim_strsave(xpc.xp_pattern); + else + pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); + + if (rettv_list_alloc(rettv) == OK && pat != NULL) + { + int i; + + ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); + + for (i = 0; i < xpc.xp_numfiles; i++) + list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); + } + vim_free(pat); + ExpandCleanup(&xpc); +} +#endif // FEAT_EVAL diff --git a/src/cmdhist.c b/src/cmdhist.c new file mode 100644 index 0000000..d398ca7 --- /dev/null +++ b/src/cmdhist.c @@ -0,0 +1,785 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * cmdhist.c: Functions for the history of the command-line. + */ + +#include "vim.h" + +static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL}; +static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; // lastused entry +static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0}; + // identifying (unique) number of newest history entry +static int hislen = 0; // actual length of history tables + +/* + * Return the length of the history tables + */ + int +get_hislen(void) +{ + return hislen; +} + +/* + * Return a pointer to a specified history table + */ + histentry_T * +get_histentry(int hist_type) +{ + return history[hist_type]; +} + +#if defined(FEAT_VIMINFO) || defined(PROTO) + void +set_histentry(int hist_type, histentry_T *entry) +{ + history[hist_type] = entry; +} +#endif + + int * +get_hisidx(int hist_type) +{ + return &hisidx[hist_type]; +} + +#if defined(FEAT_VIMINFO) || defined(PROTO) + int * +get_hisnum(int hist_type) +{ + return &hisnum[hist_type]; +} +#endif + +/* + * Translate a history character to the associated type number. + */ + int +hist_char2type(int c) +{ + if (c == ':') + return HIST_CMD; + if (c == '=') + return HIST_EXPR; + if (c == '@') + return HIST_INPUT; + if (c == '>') + return HIST_DEBUG; + return HIST_SEARCH; // must be '?' or '/' +} + +/* + * Table of history names. + * These names are used in :history and various hist...() functions. + * It is sufficient to give the significant prefix of a history name. + */ + +static char *(history_names[]) = +{ + "cmd", + "search", + "expr", + "input", + "debug", + NULL +}; + +/* + * Function given to ExpandGeneric() to obtain the possible first + * arguments of the ":history command. + */ + char_u * +get_history_arg(expand_T *xp UNUSED, int idx) +{ + char *short_names = ":=@>?/"; + int short_names_count = (int)STRLEN(short_names); + int history_name_count = ARRAY_LENGTH(history_names) - 1; + + if (idx < short_names_count) + { + xp->xp_buf[0] = (char_u)short_names[idx]; + xp->xp_buf[1] = NUL; + return xp->xp_buf; + } + if (idx < short_names_count + history_name_count) + return (char_u *)history_names[idx - short_names_count]; + if (idx == short_names_count + history_name_count) + return (char_u *)"all"; + return NULL; +} + +/* + * init_history() - Initialize the command line history. + * Also used to re-allocate the history when the size changes. + */ + void +init_history(void) +{ + int newlen; // new length of history table + histentry_T *temp; + int i; + int j; + int type; + + // If size of history table changed, reallocate it + newlen = (int)p_hi; + if (newlen == hislen) // history length didn't change + return; + + // history length changed + for (type = 0; type < HIST_COUNT; ++type) // adjust the tables + { + if (newlen > 0) + { + temp = ALLOC_MULT(histentry_T, newlen); + if (temp == NULL) // out of memory! + { + if (type == 0) // first one: just keep the old length + { + newlen = hislen; + break; + } + // Already changed one table, now we can only have zero + // length for all tables. + newlen = 0; + type = -1; + continue; + } + } + else + temp = NULL; + + if (hisidx[type] < 0) // there are no entries yet + { + for (i = 0; i < newlen; ++i) + clear_hist_entry(&temp[i]); + } + else if (newlen > hislen) // array becomes bigger + { + for (i = 0; i <= hisidx[type]; ++i) + temp[i] = history[type][i]; + j = i; + for ( ; i <= newlen - (hislen - hisidx[type]); ++i) + clear_hist_entry(&temp[i]); + for ( ; j < hislen; ++i, ++j) + temp[i] = history[type][j]; + } + else // array becomes smaller or 0 + { + j = hisidx[type]; + for (i = newlen - 1; ; --i) + { + if (i >= 0) // copy newest entries + temp[i] = history[type][j]; + else // remove older entries + vim_free(history[type][j].hisstr); + if (--j < 0) + j = hislen - 1; + if (j == hisidx[type]) + break; + } + hisidx[type] = newlen - 1; + } + vim_free(history[type]); + history[type] = temp; + } + hislen = newlen; +} + + void +clear_hist_entry(histentry_T *hisptr) +{ + hisptr->hisnum = 0; + hisptr->viminfo = FALSE; + hisptr->hisstr = NULL; + hisptr->time_set = 0; +} + +/* + * Check if command line 'str' is already in history. + * If 'move_to_front' is TRUE, matching entry is moved to end of history. + */ + int +in_history( + int type, + char_u *str, + int move_to_front, // Move the entry to the front if it exists + int sep, + int writing) // ignore entries read from viminfo +{ + int i; + int last_i = -1; + char_u *p; + + if (hisidx[type] < 0) + return FALSE; + i = hisidx[type]; + do + { + if (history[type][i].hisstr == NULL) + return FALSE; + + // For search history, check that the separator character matches as + // well. + p = history[type][i].hisstr; + if (STRCMP(str, p) == 0 + && !(writing && history[type][i].viminfo) + && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1])) + { + if (!move_to_front) + return TRUE; + last_i = i; + break; + } + if (--i < 0) + i = hislen - 1; + } while (i != hisidx[type]); + + if (last_i < 0) + return FALSE; + + str = history[type][i].hisstr; + while (i != hisidx[type]) + { + if (++i >= hislen) + i = 0; + history[type][last_i] = history[type][i]; + last_i = i; + } + history[type][i].hisnum = ++hisnum[type]; + history[type][i].viminfo = FALSE; + history[type][i].hisstr = str; + history[type][i].time_set = vim_time(); + return TRUE; +} + +/* + * Convert history name (from table above) to its HIST_ equivalent. + * When "name" is empty, return "cmd" history. + * Returns -1 for unknown history name. + */ + static int +get_histtype(char_u *name) +{ + int i; + int len = (int)STRLEN(name); + + // No argument: use current history. + if (len == 0) + return hist_char2type(get_cmdline_firstc()); + + for (i = 0; history_names[i] != NULL; ++i) + if (STRNICMP(name, history_names[i], len) == 0) + return i; + + if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && name[1] == NUL) + return hist_char2type(name[0]); + + return -1; +} + +static int last_maptick = -1; // last seen maptick + +/* + * Add the given string to the given history. If the string is already in the + * history then it is moved to the front. "histype" may be one of he HIST_ + * values. + */ + void +add_to_history( + int histype, + char_u *new_entry, + int in_map, // consider maptick when inside a mapping + int sep) // separator character used (search hist) +{ + histentry_T *hisptr; + int len; + + if (hislen == 0) // no history + return; + + if ((cmdmod.cmod_flags & CMOD_KEEPPATTERNS) && histype == HIST_SEARCH) + return; + + // Searches inside the same mapping overwrite each other, so that only + // the last line is kept. Be careful not to remove a line that was moved + // down, only lines that were added. + if (histype == HIST_SEARCH && in_map) + { + if (maptick == last_maptick && hisidx[HIST_SEARCH] >= 0) + { + // Current line is from the same mapping, remove it + hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]]; + vim_free(hisptr->hisstr); + clear_hist_entry(hisptr); + --hisnum[histype]; + if (--hisidx[HIST_SEARCH] < 0) + hisidx[HIST_SEARCH] = hislen - 1; + } + last_maptick = -1; + } + + if (in_history(histype, new_entry, TRUE, sep, FALSE)) + return; + + if (++hisidx[histype] == hislen) + hisidx[histype] = 0; + hisptr = &history[histype][hisidx[histype]]; + vim_free(hisptr->hisstr); + + // Store the separator after the NUL of the string. + len = (int)STRLEN(new_entry); + hisptr->hisstr = vim_strnsave(new_entry, len + 2); + if (hisptr->hisstr != NULL) + hisptr->hisstr[len + 1] = sep; + + hisptr->hisnum = ++hisnum[histype]; + hisptr->viminfo = FALSE; + hisptr->time_set = vim_time(); + if (histype == HIST_SEARCH && in_map) + last_maptick = maptick; +} + +#if defined(FEAT_EVAL) || defined(PROTO) + +/* + * Get identifier of newest history entry. + * "histype" may be one of the HIST_ values. + */ + static int +get_history_idx(int histype) +{ + if (hislen == 0 || histype < 0 || histype >= HIST_COUNT + || hisidx[histype] < 0) + return -1; + + return history[histype][hisidx[histype]].hisnum; +} + +/* + * Calculate history index from a number: + * num > 0: seen as identifying number of a history entry + * num < 0: relative position in history wrt newest entry + * "histype" may be one of the HIST_ values. + */ + static int +calc_hist_idx(int histype, int num) +{ + int i; + histentry_T *hist; + int wrapped = FALSE; + + if (hislen == 0 || histype < 0 || histype >= HIST_COUNT + || (i = hisidx[histype]) < 0 || num == 0) + return -1; + + hist = history[histype]; + if (num > 0) + { + while (hist[i].hisnum > num) + if (--i < 0) + { + if (wrapped) + break; + i += hislen; + wrapped = TRUE; + } + if (i >= 0 && hist[i].hisnum == num && hist[i].hisstr != NULL) + return i; + } + else if (-num <= hislen) + { + i += num + 1; + if (i < 0) + i += hislen; + if (hist[i].hisstr != NULL) + return i; + } + return -1; +} + +/* + * Get a history entry by its index. + * "histype" may be one of the HIST_ values. + */ + static char_u * +get_history_entry(int histype, int idx) +{ + idx = calc_hist_idx(histype, idx); + if (idx >= 0) + return history[histype][idx].hisstr; + else + return (char_u *)""; +} + +/* + * Clear all entries of a history. + * "histype" may be one of the HIST_ values. + */ + static int +clr_history(int histype) +{ + int i; + histentry_T *hisptr; + + if (hislen != 0 && histype >= 0 && histype < HIST_COUNT) + { + hisptr = history[histype]; + for (i = hislen; i--;) + { + vim_free(hisptr->hisstr); + clear_hist_entry(hisptr); + hisptr++; + } + hisidx[histype] = -1; // mark history as cleared + hisnum[histype] = 0; // reset identifier counter + return OK; + } + return FAIL; +} + +/* + * Remove all entries matching {str} from a history. + * "histype" may be one of the HIST_ values. + */ + static int +del_history_entry(int histype, char_u *str) +{ + regmatch_T regmatch; + histentry_T *hisptr; + int idx; + int i; + int last; + int found = FALSE; + + if (hislen == 0 || histype < 0 || histype >= HIST_COUNT || *str == NUL + || hisidx[histype] < 0) + return FALSE; + + idx = hisidx[histype]; + regmatch.regprog = vim_regcomp(str, RE_MAGIC + RE_STRING); + if (regmatch.regprog == NULL) + return FALSE; + + regmatch.rm_ic = FALSE; // always match case + + i = last = idx; + do + { + hisptr = &history[histype][i]; + if (hisptr->hisstr == NULL) + break; + if (vim_regexec(®match, hisptr->hisstr, (colnr_T)0)) + { + found = TRUE; + vim_free(hisptr->hisstr); + clear_hist_entry(hisptr); + } + else + { + if (i != last) + { + history[histype][last] = *hisptr; + clear_hist_entry(hisptr); + } + if (--last < 0) + last += hislen; + } + if (--i < 0) + i += hislen; + } while (i != idx); + + if (history[histype][idx].hisstr == NULL) + hisidx[histype] = -1; + + vim_regfree(regmatch.regprog); + return found; +} + +/* + * Remove an indexed entry from a history. + * "histype" may be one of the HIST_ values. + */ + static int +del_history_idx(int histype, int idx) +{ + int i, j; + + i = calc_hist_idx(histype, idx); + if (i < 0) + return FALSE; + idx = hisidx[histype]; + vim_free(history[histype][i].hisstr); + + // When deleting the last added search string in a mapping, reset + // last_maptick, so that the last added search string isn't deleted again. + if (histype == HIST_SEARCH && maptick == last_maptick && i == idx) + last_maptick = -1; + + while (i != idx) + { + j = (i + 1) % hislen; + history[histype][i] = history[histype][j]; + i = j; + } + clear_hist_entry(&history[histype][i]); + if (--i < 0) + i += hislen; + hisidx[histype] = i; + return TRUE; +} + +/* + * "histadd()" function + */ + void +f_histadd(typval_T *argvars UNUSED, typval_T *rettv) +{ + int histype; + char_u *str; + char_u buf[NUMBUFLEN]; + + rettv->vval.v_number = FALSE; + if (check_secure()) + return; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + str = tv_get_string_chk(&argvars[0]); // NULL on type error + histype = str != NULL ? get_histtype(str) : -1; + if (histype < 0) + return; + + str = tv_get_string_buf(&argvars[1], buf); + if (*str == NUL) + return; + + init_history(); + add_to_history(histype, str, FALSE, NUL); + rettv->vval.v_number = TRUE; +} + +/* + * "histdel()" function + */ + void +f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ + int n; + char_u buf[NUMBUFLEN]; + char_u *str; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_opt_string_or_number_arg(argvars, 1) == FAIL)) + return; + + str = tv_get_string_chk(&argvars[0]); // NULL on type error + if (str == NULL) + n = 0; + else if (argvars[1].v_type == VAR_UNKNOWN) + // only one argument: clear entire history + n = clr_history(get_histtype(str)); + else if (argvars[1].v_type == VAR_NUMBER) + // index given: remove that entry + n = del_history_idx(get_histtype(str), + (int)tv_get_number(&argvars[1])); + else + // string given: remove all matching entries + n = del_history_entry(get_histtype(str), + tv_get_string_buf(&argvars[1], buf)); + rettv->vval.v_number = n; +} + +/* + * "histget()" function + */ + void +f_histget(typval_T *argvars UNUSED, typval_T *rettv) +{ + int type; + int idx; + char_u *str; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_opt_number_arg(argvars, 1) == FAIL)) + return; + + str = tv_get_string_chk(&argvars[0]); // NULL on type error + if (str == NULL) + rettv->vval.v_string = NULL; + else + { + type = get_histtype(str); + if (argvars[1].v_type == VAR_UNKNOWN) + idx = get_history_idx(type); + else + idx = (int)tv_get_number_chk(&argvars[1], NULL); + // -1 on type error + rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); + } + rettv->v_type = VAR_STRING; +} + +/* + * "histnr()" function + */ + void +f_histnr(typval_T *argvars UNUSED, typval_T *rettv) +{ + int i; + char_u *histname; + + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + + histname = tv_get_string_chk(&argvars[0]); + i = histname == NULL ? HIST_CMD - 1 : get_histtype(histname); + if (i >= HIST_CMD && i < HIST_COUNT) + i = get_history_idx(i); + else + i = -1; + rettv->vval.v_number = i; +} +#endif // FEAT_EVAL + +#if defined(FEAT_CRYPT) || defined(PROTO) +/* + * Very specific function to remove the value in ":set key=val" from the + * history. + */ + void +remove_key_from_history(void) +{ + char_u *p; + int i; + + i = hisidx[HIST_CMD]; + if (i < 0) + return; + p = history[HIST_CMD][i].hisstr; + if (p == NULL) + return; + + for ( ; *p; ++p) + if (STRNCMP(p, "key", 3) == 0 && !isalpha(p[3])) + { + p = vim_strchr(p + 3, '='); + if (p == NULL) + break; + ++p; + for (i = 0; p[i] && !VIM_ISWHITE(p[i]); ++i) + if (p[i] == '\\' && p[i + 1]) + ++i; + STRMOVE(p, p + i); + --p; + } +} +#endif + +/* + * :history command - print a history + */ + void +ex_history(exarg_T *eap) +{ + histentry_T *hist; + int histype1 = HIST_CMD; + int histype2 = HIST_CMD; + int hisidx1 = 1; + int hisidx2 = -1; + int idx; + int i, j, k; + char_u *end; + char_u *arg = eap->arg; + + if (hislen == 0) + { + msg(_("'history' option is zero")); + return; + } + + if (!(VIM_ISDIGIT(*arg) || *arg == '-' || *arg == ',')) + { + end = arg; + while (ASCII_ISALPHA(*end) + || vim_strchr((char_u *)":=@>/?", *end) != NULL) + end++; + i = *end; + *end = NUL; + histype1 = get_histtype(arg); + if (histype1 == -1) + { + if (STRNICMP(arg, "all", STRLEN(arg)) == 0) + { + histype1 = 0; + histype2 = HIST_COUNT-1; + } + else + { + *end = i; + semsg(_(e_trailing_characters_str), arg); + return; + } + } + else + histype2 = histype1; + *end = i; + } + else + end = arg; + if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL) + { + semsg(_(e_trailing_characters_str), end); + return; + } + + for (; !got_int && histype1 <= histype2; ++histype1) + { + STRCPY(IObuff, "\n # "); + STRCAT(STRCAT(IObuff, history_names[histype1]), " history"); + msg_puts_title((char *)IObuff); + idx = hisidx[histype1]; + hist = history[histype1]; + j = hisidx1; + k = hisidx2; + if (j < 0) + j = (-j > hislen) ? 0 : hist[(hislen+j+idx+1) % hislen].hisnum; + if (k < 0) + k = (-k > hislen) ? 0 : hist[(hislen+k+idx+1) % hislen].hisnum; + if (idx >= 0 && j <= k) + for (i = idx + 1; !got_int; ++i) + { + if (i == hislen) + i = 0; + if (hist[i].hisstr != NULL + && hist[i].hisnum >= j && hist[i].hisnum <= k) + { + msg_putchar('\n'); + sprintf((char *)IObuff, "%c%6d ", i == idx ? '>' : ' ', + hist[i].hisnum); + if (vim_strsize(hist[i].hisstr) > (int)Columns - 10) + trunc_string(hist[i].hisstr, IObuff + STRLEN(IObuff), + (int)Columns - 10, IOSIZE - (int)STRLEN(IObuff)); + else + STRCAT(IObuff, hist[i].hisstr); + msg_outtrans(IObuff); + out_flush(); + } + if (i == idx) + break; + } + } +} diff --git a/src/config.h.in b/src/config.h.in new file mode 100644 index 0000000..6cb43da --- /dev/null +++ b/src/config.h.in @@ -0,0 +1,501 @@ +/* + * config.h.in. Originally generated automatically from configure.ac by + * autoheader and manually changed after that. + */ + +/* Define if we have EBCDIC code */ +#undef EBCDIC + +/* Define unless no X support found */ +#undef HAVE_X11 + +/* Define when terminfo support found */ +#undef TERMINFO + +/* Define when termcap.h contains ospeed */ +#undef HAVE_OSPEED + +/* Define when ospeed can be extern */ +#undef OSPEED_EXTERN + +/* Define when termcap.h contains UP, BC and PC */ +#undef HAVE_UP_BC_PC + +/* Define when UP, BC and PC can be extern */ +#undef UP_BC_PC_EXTERN + +/* Define when termcap.h defines outfuntype */ +#undef HAVE_OUTFUNTYPE + +/* Define when del_curterm() is available */ +#undef HAVE_DEL_CURTERM + +/* Define when __DATE__ " " __TIME__ can be used */ +#undef HAVE_DATE_TIME + +/* Defined from $SOURCE_DATE_EPOCH, used as the build date */ +#undef BUILD_DATE + +/* Define when __attribute__((unused)) can be used */ +#undef HAVE_ATTRIBUTE_UNUSED + +/* defined always when using configure */ +#undef UNIX + +/* Defined to the size of an int */ +#undef VIM_SIZEOF_INT + +/* Defined to the size of a long */ +#undef VIM_SIZEOF_LONG + +/* Defined to the size of off_t */ +#undef SIZEOF_OFF_T + +/* Defined to the size of time_t */ +#undef SIZEOF_TIME_T + +/* Define when wchar_t is only 2 bytes. */ +#undef SMALL_WCHAR_T + +/* + * If we cannot trust one of the following from the libraries, we use our + * own safe but probably slower vim_memmove(). + */ +#undef USEBCOPY +#undef USEMEMMOVE +#undef USEMEMCPY + +/* Define when "man -s 2" is to be used */ +#undef USEMAN_S + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to empty if the keyword does not work. */ +#undef volatile + +/* Define to `int' if doesn't define. */ +#undef mode_t + +/* Define to `long' if doesn't define. */ +#undef off_t + +/* Define to `long' if doesn't define. */ +#undef pid_t + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Define to `unsigned int' or other type that is 32 bit. */ +#undef uint32_t + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define to `long' if doesn't define. */ +#undef ino_t + +/* Define to `unsigned' if doesn't define. */ +#undef dev_t + +/* Define on big-endian machines */ +#undef WORDS_BIGENDIAN + +/* Define to `unsigned long' if doesn't define. */ +#undef rlim_t + +/* Define to `struct sigaltstack' if doesn't define. */ +#undef stack_t + +/* Define if stack_t has the ss_base field. */ +#undef HAVE_SS_BASE + +/* Define if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define if you can safely include both and . */ +#undef SYS_SELECT_WITH_SYS_TIME + +/* Define to a typecast for select() arguments 2, 3 and 4. */ +#undef SELECT_TYPE_ARG234 + +/* Define if you have /dev/ptc */ +#undef HAVE_DEV_PTC + +/* Define if you have Sys4 ptys */ +#undef HAVE_SVR4_PTYS + +/* Define to range of pty names to try */ +#undef PTYRANGE0 +#undef PTYRANGE1 + +/* Define if struct sigcontext is present */ +#undef HAVE_SIGCONTEXT + +/* Define if toupper/tolower only work on lower/uppercase characters */ +#undef BROKEN_TOUPPER + +/* Define if stat() ignores a trailing slash */ +#undef STAT_IGNORES_SLASH + +/* Define to nanoseconds field of struct stat */ +#undef ST_MTIM_NSEC + +/* Define if tgetstr() has a second argument that is (char *) */ +#undef TGETSTR_CHAR_P + +/* Define if tgetent() returns zero for an error */ +#undef TGETENT_ZERO_ERR + +/* Define if the getcwd() function should not be used. */ +#undef BAD_GETCWD + +/* Define if you the function: */ +#undef HAVE_FCHDIR +#undef HAVE_FCHOWN +#undef HAVE_FCHMOD +#undef HAVE_FSEEKO +#undef HAVE_FSYNC +#undef HAVE_FTRUNCATE +#undef HAVE_GETCWD +#undef HAVE_GETPGID +#undef HAVE_GETPSEUDOTTY +#undef HAVE_GETPWENT +#undef HAVE_GETPWNAM +#undef HAVE_GETPWUID +#undef HAVE_GETRLIMIT +#undef HAVE_GETTIMEOFDAY +#undef HAVE_GETWD +#undef HAVE_ICONV +#undef HAVE_INET_NTOP +#undef HAVE_LOCALTIME_R +#undef HAVE_LSTAT +#undef HAVE_MEMSET +#undef HAVE_MKDTEMP +#undef HAVE_NANOSLEEP +#undef HAVE_NL_LANGINFO_CODESET +#undef HAVE_OPENDIR +#undef HAVE_POSIX_OPENPT +#undef HAVE_PUTENV +#undef HAVE_QSORT +#undef HAVE_READLINK +#undef HAVE_RENAME +#undef HAVE_SELECT +#undef HAVE_SELINUX +#undef HAVE_SETENV +#undef HAVE_SETPGID +#undef HAVE_SETSID +#undef HAVE_SIGACTION +#undef HAVE_SIGALTSTACK +#undef HAVE_SIGSET +#undef HAVE_SIGSETJMP +#undef HAVE_SIGSTACK +#undef HAVE_SIGPROCMASK +#undef HAVE_SIGVEC +#undef HAVE_SMACK +#undef HAVE_STRCASECMP +#undef HAVE_STRCOLL +#undef HAVE_STRERROR +#undef HAVE_STRFTIME +#undef HAVE_STRICMP +#undef HAVE_STRNCASECMP +#undef HAVE_STRNICMP +#undef HAVE_STRPBRK +#undef HAVE_STRPTIME +#undef HAVE_STRTOL +#undef HAVE_CANBERRA +#undef HAVE_SODIUM +#undef HAVE_ST_BLKSIZE +#undef HAVE_SYSCONF +#undef HAVE_SYSCTL +#undef HAVE_SYSINFO +#undef HAVE_SYSINFO_MEM_UNIT +#undef HAVE_SYSINFO_UPTIME +#undef HAVE_TGETENT +#undef HAVE_TOWLOWER +#undef HAVE_TOWUPPER +#undef HAVE_ISWUPPER +#undef HAVE_TZSET +#undef HAVE_UNSETENV +#undef HAVE_USLEEP +#undef HAVE_UTIME +#undef HAVE_BIND_TEXTDOMAIN_CODESET +#undef HAVE_MBLEN +#undef HAVE_TIMER_CREATE + +/* Define, if needed, for accessing large files. */ +#undef _LARGE_FILES +#undef _FILE_OFFSET_BITS +#undef _LARGEFILE_SOURCE + +/* Define if you do not have utime(), but do have the utimes() function. */ +#undef HAVE_UTIMES + +/* Define if you have the header file: */ +#undef HAVE_DIRENT_H +#undef HAVE_DISPATCH_DISPATCH_H +#undef HAVE_ERRNO_H +#undef HAVE_FCNTL_H +#undef HAVE_FRAME_H +#undef HAVE_ICONV_H +#undef HAVE_INTTYPES_H +#undef HAVE_LANGINFO_H +#undef HAVE_LIBC_H +#undef HAVE_LIBGEN_H +#undef HAVE_LIBINTL_H +#undef HAVE_LOCALE_H +#undef HAVE_MATH_H +#undef HAVE_NDIR_H +#undef HAVE_POLL_H +#undef HAVE_PTHREAD_NP_H +#undef HAVE_PWD_H +#undef HAVE_SETJMP_H +#undef HAVE_SGTTY_H +#undef HAVE_STDINT_H +#undef HAVE_STRINGS_H +#undef HAVE_STROPTS_H +#undef HAVE_SYS_ACCESS_H +#undef HAVE_SYS_ACL_H +#undef HAVE_SYS_DIR_H +#undef HAVE_SYS_IOCTL_H +#undef HAVE_SYS_NDIR_H +#undef HAVE_SYS_PARAM_H +#undef HAVE_SYS_POLL_H +#undef HAVE_SYS_PTEM_H +#undef HAVE_SYS_PTMS_H +#undef HAVE_SYS_RESOURCE_H +#undef HAVE_SYS_SELECT_H +#undef HAVE_SYS_STATFS_H +#undef HAVE_SYS_STREAM_H +#undef HAVE_SYS_SYSCTL_H +#undef HAVE_SYS_SYSINFO_H +#undef HAVE_SYS_SYSTEMINFO_H +#undef HAVE_SYS_TIME_H +#undef HAVE_SYS_TYPES_H +#undef HAVE_SYS_UTSNAME_H +#undef HAVE_TERMCAP_H +#undef HAVE_TERMIOS_H +#undef HAVE_TERMIO_H +#undef HAVE_WCHAR_H +#undef HAVE_WCTYPE_H +#undef HAVE_UNISTD_H +#undef HAVE_UTIL_DEBUG_H +#undef HAVE_UTIL_MSGI18N_H +#undef HAVE_UTIME_H +#undef HAVE_X11_SUNKEYSYM_H +#undef HAVE_XM_XM_H +#undef HAVE_XM_XPMP_H +#undef HAVE_XM_TRAITP_H +#undef HAVE_XM_MANAGER_H +#undef HAVE_XM_UNHIGHLIGHTT_H +#undef HAVE_XM_JOINSIDET_H +#undef HAVE_XM_NOTEBOOK_H +#undef HAVE_X11_XPM_H +#undef HAVE_X11_XMU_EDITRES_H +#undef HAVE_X11_SM_SMLIB_H + +/* Define to the type of the XpmAttributes type. */ +#undef XPMATTRIBUTES_TYPE + +/* Define if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if you have a that is not POSIX.1 compatible. */ +#undef HAVE_UNION_WAIT + +/* This is currently unused in vim: */ +/* Define if you have the ANSI C header files. */ +/* #undef STDC_HEADERS */ + +/* instead, we check a few STDC things ourselves */ +#undef HAVE_STDLIB_H +#undef HAVE_STRING_H + +/* Define if strings.h cannot be included when strings.h already is */ +#undef NO_STRINGS_WITH_STRING_H + +/* Define if you want tiny features. */ +#undef FEAT_TINY + +/* Define if you want normal features. */ +#undef FEAT_NORMAL + +/* Define if you want huge features. */ +#undef FEAT_HUGE + +/* Define if you want to include the Lua interpreter. */ +#undef FEAT_LUA + +/* Define for linking via dlopen() or LoadLibrary() */ +#undef DYNAMIC_LUA + +/* Define if you want to include the MzScheme interpreter. */ +#undef FEAT_MZSCHEME + +/* Define if you want to include the Perl interpreter. */ +#undef FEAT_PERL + +/* Define for linking via dlopen() or LoadLibrary() */ +#undef DYNAMIC_PERL + +/* Define if you want to include the Python interpreter. */ +#undef FEAT_PYTHON + +/* Define if you want to include the Python3 interpreter. */ +#undef FEAT_PYTHON3 + +/* Define for linking via dlopen() or LoadLibrary() */ +#undef DYNAMIC_PYTHON + +/* Define for linking via dlopen() or LoadLibrary() */ +#undef DYNAMIC_PYTHON3 + +/* Define if dynamic python does not require RTLD_GLOBAL */ +#undef PY_NO_RTLD_GLOBAL + +/* Define if dynamic python3 does not require RTLD_GLOBAL */ +#undef PY3_NO_RTLD_GLOBAL + +/* Define if you want to include the Ruby interpreter. */ +#undef FEAT_RUBY + +/* Define for linking via dlopen() or LoadLibrary() */ +#undef DYNAMIC_RUBY + +/* Define if you want to include the Tcl interpreter. */ +#undef FEAT_TCL + +/* Define for linking via dlopen() or LoadLibrary() */ +#undef DYNAMIC_TCL + +/* Define if you want to add support for ACL */ +#undef HAVE_POSIX_ACL +#undef HAVE_SOLARIS_ZFS_ACL +#undef HAVE_SOLARIS_ACL +#undef HAVE_AIX_ACL + +/* Define if pango_shape_full() is available. */ +#undef HAVE_PANGO_SHAPE_FULL + +/* Define if you want to add support of GPM (Linux console mouse daemon) */ +#undef HAVE_GPM + +/* Define if you want to add support of sysmouse (*BSD console mouse) */ +#undef HAVE_SYSMOUSE + +/* Define if you want to include the Cscope interface. */ +#undef FEAT_CSCOPE + +/* Define if you don't want to include right-left support. */ +#undef DISABLE_RIGHTLEFT + +/* Define if you don't want to include Arabic support. */ +#undef DISABLE_ARABIC + +/* Define if you want to always define a server name at vim startup. */ +#undef FEAT_AUTOSERVERNAME + +/* Define if you want to include fontset support. */ +#undef FEAT_XFONTSET + +/* Define if you want to include XIM support. */ +#undef FEAT_XIM + +/* Define if you use GTK and want GNOME support. */ +#undef FEAT_GUI_GNOME + +/* Define if you use KDE and want KDE Toolbar support. */ +#undef FEAT_KDETOOLBAR + +/* Define if your X has own locale library */ +#undef X_LOCALE + +/* Define if we have dlfcn.h. */ +#undef HAVE_DLFCN_H + +/* Define if there is a working gettext(). */ +#undef HAVE_GETTEXT + +/* Define if _nl_msg_cat_cntr is present. */ +#undef HAVE_NL_MSG_CAT_CNTR + +/* Define if we have dlopen() */ +#undef HAVE_DLOPEN + +/* Define if we have dlsym() */ +#undef HAVE_DLSYM + +/* Define if we have dl.h. */ +#undef HAVE_DL_H + +/* Define if we have shl_load() */ +#undef HAVE_SHL_LOAD + +/* Define if we can use IPv6 networking. */ +#undef FEAT_IPV6 + +/* Define if you want to include NetBeans integration. */ +#undef FEAT_NETBEANS_INTG + +/* Define if you want to include process communication. */ +#undef FEAT_JOB_CHANNEL + +/* Define if you want to include terminal emulator support. */ +#undef FEAT_TERMINAL + +// Define default global runtime path. +#undef RUNTIME_GLOBAL + +// Define default global runtime after path. +#undef RUNTIME_GLOBAL_AFTER + +/* Define name of who modified a released Vim */ +#undef MODIFIED_BY + +/* Define if you want XSMP interaction as well as vanilla swapfile safety */ +#undef USE_XSMP_INTERACT + +/* Define if fcntl()'s F_SETFD command knows about FD_CLOEXEC */ +#undef HAVE_FD_CLOEXEC + +/* Define if /proc/self/exe or similar can be read */ +#undef PROC_EXE_LINK + +/* Define if you want Cygwin to use the WIN32 clipboard, not compatible with X11*/ +#undef FEAT_CYGWIN_WIN32_CLIPBOARD + +/* Define if we have AvailabilityMacros.h on Mac OS X */ +#undef HAVE_AVAILABILITYMACROS_H + +/* Define if Xutf8SetWMProperties() is in an X library. */ +#undef HAVE_XUTF8SETWMPROPERTIES + +/* Define if GResource is used to load icons */ +#undef USE_GRESOURCE + +/* Define if GTK+ GUI is to be linked against GTK+ 3 */ +#undef USE_GTK3 + +/* Define if we have isinf() */ +#undef HAVE_ISINF + +/* Define if we have isnan() */ +#undef HAVE_ISNAN + +/* Define if we have dirfd() */ +#undef HAVE_DIRFD + +/* Define if we have flock() */ +#undef HAVE_FLOCK + +/* Define to inline symbol or empty */ +#undef inline + +/* Define if _SC_SIGSTKSZ is available via sysconf() */ +#undef HAVE_SYSCONF_SIGSTKSZ + +/* Define if you want to load libgpm dynamically */ +#undef DYNAMIC_GPM diff --git a/src/config.mk.dist b/src/config.mk.dist new file mode 100644 index 0000000..8a584c2 --- /dev/null +++ b/src/config.mk.dist @@ -0,0 +1,5 @@ +the first target to make vim is: reconfig +srcdir = . +VIMNAME = vim +EXNAME = ex +VIEWNAME = view diff --git a/src/config.mk.in b/src/config.mk.in new file mode 100644 index 0000000..4eb6928 --- /dev/null +++ b/src/config.mk.in @@ -0,0 +1,186 @@ +# +# config.mk.in -- autoconf template for Vim on Unix vim:ts=8:sw=8: +# +# DO NOT EDIT config.mk!! It will be overwritten by configure. +# Edit Makefile and run "make" or run ./configure with other arguments. +# +# Configure does not edit the makefile directly. This method is not the +# standard use of GNU autoconf, but it has two advantages: +# a) The user can override every choice made by configure. +# b) Modifications to the makefile are not lost when configure is run. +# +# I hope this is worth being nonstandard. jw. + +@SET_MAKE@ + +VIMNAME = @VIMNAME@ +EXNAME = @EXNAME@ +VIEWNAME = @VIEWNAME@ + +CC = @CC@ +DEFS = @DEFS@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +srcdir = @srcdir@ +VPATH = @srcdir@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +TAGPRG = @TAGPRG@ + +CPP = @CPP@ +CPP_MM = @CPP_MM@ +DEPEND_CFLAGS_FILTER = @DEPEND_CFLAGS_FILTER@ +LINK_AS_NEEDED = @LINK_AS_NEEDED@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS_DIR = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIB@ + +XDIFF_OBJS_USED = @XDIFF_OBJS_USED@ + +LUA_LIBS = @LUA_LIBS@ +LUA_SRC = @LUA_SRC@ +LUA_OBJ = @LUA_OBJ@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_CFLAGS_EXTRA = @LUA_CFLAGS_EXTRA@ +LUA_PRO = @LUA_PRO@ + +MZSCHEME_LIBS = @MZSCHEME_LIBS@ +MZSCHEME_SRC = @MZSCHEME_SRC@ +MZSCHEME_OBJ = @MZSCHEME_OBJ@ +MZSCHEME_CFLAGS = @MZSCHEME_CFLAGS@ +MZSCHEME_PRO = @MZSCHEME_PRO@ +MZSCHEME_EXTRA = @MZSCHEME_EXTRA@ +MZSCHEME_MZC = @MZSCHEME_MZC@ + +PERL = @vi_cv_path_perl@ +PERLLIB = @vi_cv_perllib@ +PERL_XSUBPP = @vi_cv_perl_xsubpp@ +PERL_LIBS = @PERL_LIBS@ +SHRPENV = @shrpenv@ +PERL_SRC = @PERL_SRC@ +PERL_OBJ = @PERL_OBJ@ +PERL_PRO = @PERL_PRO@ +PERL_CFLAGS = @PERL_CFLAGS@ +PERL_CFLAGS_EXTRA = @PERL_CFLAGS_EXTRA@ + +PYTHON_SRC = @PYTHON_SRC@ +PYTHON_OBJ = @PYTHON_OBJ@ +PYTHON_CFLAGS = @PYTHON_CFLAGS@ +PYTHON_CFLAGS_EXTRA = @PYTHON_CFLAGS_EXTRA@ +PYTHON_LIBS = @PYTHON_LIBS@ + +PYTHON3_SRC = @PYTHON3_SRC@ +PYTHON3_OBJ = @PYTHON3_OBJ@ +PYTHON3_CFLAGS = @PYTHON3_CFLAGS@ +PYTHON3_CFLAGS_EXTRA = @PYTHON3_CFLAGS_EXTRA@ +PYTHON3_LIBS = @PYTHON3_LIBS@ + +TCL = @vi_cv_path_tcl@ +TCL_SRC = @TCL_SRC@ +TCL_OBJ = @TCL_OBJ@ +TCL_PRO = @TCL_PRO@ +TCL_CFLAGS = @TCL_CFLAGS@ +TCL_CFLAGS_EXTRA = @TCL_CFLAGS_EXTRA@ +TCL_LIBS = @TCL_LIBS@ + +NETBEANS_SRC = @NETBEANS_SRC@ +NETBEANS_OBJ = @NETBEANS_OBJ@ +CHANNEL_SRC = @CHANNEL_SRC@ +CHANNEL_OBJ = @CHANNEL_OBJ@ +TERM_SRC = @TERM_SRC@ +TERM_OBJ = @TERM_OBJ@ +TERM_TEST = @TERM_TEST@ + +RUBY = @vi_cv_path_ruby@ +RUBY_SRC = @RUBY_SRC@ +RUBY_OBJ = @RUBY_OBJ@ +RUBY_PRO = @RUBY_PRO@ +RUBY_CFLAGS = @RUBY_CFLAGS@ +RUBY_CFLAGS_EXTRA = @RUBY_CFLAGS_EXTRA@ +RUBY_LIBS = @RUBY_LIBS@ + +AWK = @AWK@ + +STRIP = @STRIP@ + +EXEEXT = @EXEEXT@ +CROSS_COMPILING = @CROSS_COMPILING@ + +COMPILEDBY = @compiledby@ + +INSTALLVIMDIFF = @dovimdiff@ +INSTALLGVIMDIFF = @dogvimdiff@ +INSTALL_LANGS = @INSTALL_LANGS@ +INSTALL_TOOL_LANGS = @INSTALL_TOOL_LANGS@ + +### sed command to fix quotes while creating pathdef.c +QUOTESED = @QUOTESED@ + +### Line break character as octal number for "tr" +NL = @line_break@ + +### Top directory for everything +prefix = @prefix@ + +### Top directory for the binary +exec_prefix = @exec_prefix@ + +### Prefix for location of data files +BINDIR = @bindir@ + +### For autoconf 2.60 and later (avoid a warning) +datarootdir = @datarootdir@ + +### Prefix for location of data files +DATADIR = @datadir@ + +### Prefix for location of man pages +MANDIR = @mandir@ + +### Do we have a GUI +GUI_INC_LOC = @GUI_INC_LOC@ +GUI_LIB_LOC = @GUI_LIB_LOC@ +GUI_SRC = $(@GUITYPE@_SRC) +GUI_OBJ = $(@GUITYPE@_OBJ) +GUI_DEFS = $(@GUITYPE@_DEFS) +GUI_IPATH = $(@GUITYPE@_IPATH) +GUI_LIBS_DIR = $(@GUITYPE@_LIBS_DIR) +GUI_LIBS1 = $(@GUITYPE@_LIBS1) +GUI_LIBS2 = $(@GUITYPE@_LIBS2) +GUI_INSTALL = $(@GUITYPE@_INSTALL) +GUI_TARGETS = $(@GUITYPE@_TARGETS) +GUI_MAN_TARGETS = $(@GUITYPE@_MAN_TARGETS) +GUI_TESTTARGET = $(@GUITYPE@_TESTTARGET) +GUI_TESTARG = $(@GUITYPE@_TESTARG) +GUI_BUNDLE = $(@GUITYPE@_BUNDLE) +NARROW_PROTO = @NARROW_PROTO@ +GUI_X_LIBS = @GUI_X_LIBS@ +MOTIF_LIBNAME = @MOTIF_LIBNAME@ +GTK_LIBNAME = @GTK_LIBNAME@ + +GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ +GRESOURCE_SRC = @GRESOURCE_SRC@ +GRESOURCE_OBJ = @GRESOURCE_OBJ@ + +GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@ +UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ + +### Any OS dependent extra source and object file +OS_EXTRA_SRC = @OS_EXTRA_SRC@ +OS_EXTRA_OBJ = @OS_EXTRA_OBJ@ + +### If the *.po files are to be translated to *.mo files. +MAKEMO = @MAKEMO@ + +MSGFMT = @MSGFMT@ +MSGFMT_DESKTOP = @MSGFMT_DESKTOP@ + +### set if $SOURCE_DATE_EPOCH was set when running configure +BUILD_DATE_MSG = @BUILD_DATE_MSG@ + + +# Make sure that "make first" will run "make all" once configure has done its +# work. This is needed when using the Makefile in the top directory. +first: all diff --git a/src/configure b/src/configure new file mode 100755 index 0000000..d8595a5 --- /dev/null +++ b/src/configure @@ -0,0 +1,10 @@ +#! /bin/sh +# run the automatically generated configure script +CONFIG_STATUS=auto/config.status \ + auto/configure "$@" --srcdir="${srcdir:-.}" --cache-file=auto/config.cache +result=$? + +# Stupid autoconf 2.5x causes this file to be left behind. +if test -f configure.lineno; then rm -f configure.lineno; fi + +exit $result diff --git a/src/configure.ac b/src/configure.ac new file mode 100644 index 0000000..13f5700 --- /dev/null +++ b/src/configure.ac @@ -0,0 +1,4646 @@ +dnl configure.ac: autoconf script for Vim + +dnl Process this file with autoconf 2.69 to produce "configure". +dnl This should also work with other versions of autoconf, but 2.70 and later +dnl generate lots of hard to fix "obsolete" warnings. + +AC_INIT(vim.h) +AC_CONFIG_HEADERS(auto/config.h:config.h.in) + +dnl Being able to run configure means the system is Unix (compatible). +AC_DEFINE(UNIX) +AC_PROG_MAKE_SET + +dnl Checks for programs. +AC_PROG_CC_C99 dnl required by almost everything +AC_PROG_CPP dnl required by header file checks +AC_PROGRAM_EGREP dnl required by AC_EGREP_CPP +AC_PROG_FGREP dnl finds working grep -F +AC_ISC_POSIX dnl required by AC_C_CROSS +AC_PROG_AWK dnl required for "make html" in ../doc + +dnl Don't strip if we don't have it +AC_CHECK_PROG(STRIP, strip, strip, :) + +dnl Check for extension of executables +AC_EXEEXT + +dnl Check for standard headers. We don't use this in Vim but other stuff +dnl in autoconf needs it, where it uses STDC_HEADERS. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT + +dnl Check that the C99 features that Vim uses are supported: +if test x"$ac_cv_prog_cc_c99" != xno; then + dnl If the compiler doesn't explicitly support C99, then check + dnl for the specific features Vim uses + + AC_TYPE_LONG_LONG_INT + if test "$ac_cv_type_long_long_int" = no; then + AC_MSG_FAILURE([Compiler does not support long long int]) + fi + + AC_MSG_CHECKING([if the compiler supports trailing commas]) + trailing_commas=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ + enum { + one, + };])], + [AC_MSG_RESULT(yes); trailing_commas=yes], + [AC_MSG_RESULT(no)]) + if test "$trailing_commas" = no; then + AC_MSG_FAILURE([Compiler does not support trailing comma in enum]) + fi + + AC_MSG_CHECKING([if the compiler supports C++ comments]) + slash_comments=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], + [// C++ comments?])], + [AC_MSG_RESULT(yes); slash_comments=yes], + [AC_MSG_RESULT(no)]) + if test "$slash_comments" = no; then + AC_MSG_FAILURE([Compiler does not support C++ comments]) + fi +fi + +dnl If $SOURCE_DATE_EPOCH is present in the environment, use that as the +dnl "compiled" timestamp in :version's output. Attempt to get the formatted +dnl date using GNU date syntax, BSD date syntax, and finally falling back to +dnl just using the current time. +if test -n "$SOURCE_DATE_EPOCH"; then + DATE_FMT="%b %d %Y %H:%M:%S" + BUILD_DATE=$(LC_ALL=C date -u -d "@$SOURCE_DATE_EPOCH" "+$DATE_FMT" 2>/dev/null || LC_ALL=C date -u -r "$SOURCE_DATE_EPOCH" "+$DATE_FMT" 2>/dev/null || LC_ALL=C date -u "+$DATE_FMT") + AC_DEFINE_UNQUOTED(BUILD_DATE, ["$BUILD_DATE"]) + BUILD_DATE_MSG=-"echo -e '=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\nNOTE: build date/time is fixed: $BUILD_DATE\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-='" + AC_SUBST(BUILD_DATE_MSG) +fi + +dnl Check for the flag that fails if stuff are missing. + +AC_MSG_CHECKING(--enable-fail-if-missing argument) +AC_ARG_ENABLE(fail_if_missing, + [ --enable-fail-if-missing Fail if dependencies on additional features + specified on the command line are missing.], + [fail_if_missing="yes"], + [fail_if_missing="no"]) +AC_MSG_RESULT($fail_if_missing) + +dnl Keep original value to check later. +with_x_arg="$with_x" + +dnl Set default value for CFLAGS if none is defined or it's empty +if test -z "$CFLAGS"; then + CFLAGS="-O" + test "$GCC" = yes && CFLAGS="-O2 -fno-strength-reduce -Wall -Wno-deprecated-declarations" +fi +if test "$GCC" = yes; then + dnl method that should work for nearly all versions + gccversion=`$CC -dumpversion` + if test "x$gccversion" = "x"; then + dnl old method; fall-back for when -dumpversion doesn't work + gccversion=`$CC --version | sed -e '2,$d' -e 's/darwin.//' -e 's/^[[^0-9]]*\([[0-9]]\.[[0-9.]]*\).*$/\1/g'` + fi + dnl version 4.0.1 was reported to cause trouble on Macintosh by Marcin Dalecki + if test "$gccversion" = "3.0.1" -o "$gccversion" = "3.0.2" -o "$gccversion" = "4.0.1"; then + echo 'GCC [[34]].0.[[12]] has a bug in the optimizer, disabling "-O#"' + CFLAGS=`echo "$CFLAGS" | sed 's/-O[[23456789]]/-O/'` + else + if test "$gccversion" = "3.1" -o "$gccversion" = "3.2" -o "$gccversion" = "3.2.1" && `echo "$CFLAGS" | grep -v fno-strength-reduce >/dev/null`; then + echo 'GCC 3.1 and 3.2 have a bug in the optimizer, adding "-fno-strength-reduce"' + CFLAGS="$CFLAGS -fno-strength-reduce" + fi + fi +fi + +dnl clang-500.2.75 or around has abandoned -f[no-]strength-reduce and issues a +dnl warning when that flag is passed to. Accordingly, adjust CFLAGS based on +dnl the version number of the clang in use. +dnl Note that this does not work to get the version of clang 3.1 or 3.2. +AC_MSG_CHECKING(for clang version) +CLANG_VERSION_STRING=`$CC --version 2>/dev/null | sed -n -e 's/^.*clang[[^0-9]]*\([[0-9]][[0-9]]*\.[[0-9]][[0-9]]*\.[[0-9]][[0-9]]*\).*$/\1/p'` +if test x"$CLANG_VERSION_STRING" != x"" ; then + CLANG_MAJOR=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/\([[0-9]][[0-9]]*\)\.[[0-9]][[0-9]]*\.[[0-9]][[0-9]]*/\1/p'` + CLANG_MINOR=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/[[0-9]][[0-9]]*\.\([[0-9]][[0-9]]*\)\.[[0-9]][[0-9]]*/\1/p'` + CLANG_REVISION=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/[[0-9]][[0-9]]*\.[[0-9]][[0-9]]*\.\([[0-9]][[0-9]]*\)/\1/p'` + CLANG_VERSION=`expr $CLANG_MAJOR '*' 1000000 '+' $CLANG_MINOR '*' 1000 '+' $CLANG_REVISION` + AC_MSG_RESULT($CLANG_VERSION) + dnl If you find the same issue with versions earlier than 500.2.75, + dnl change the constant 500002075 below appropriately. To get the + dnl integer corresponding to a version number, refer to the + dnl definition of CLANG_VERSION above. + dnl Clang 11 reports "11", assume Clang 10 and later work like this. + AC_MSG_CHECKING(if clang supports -fno-strength-reduce) + if test "$CLANG_MAJOR" -ge 10 -o "$CLANG_VERSION" -ge 500002075 ; then + AC_MSG_RESULT(no) + CFLAGS=`echo "$CFLAGS" | sed -e 's/-fno-strength-reduce/ /'` + else + AC_MSG_RESULT(yes) + fi +else + AC_MSG_RESULT(N/A) +fi + +dnl If configure thinks we are cross compiling, there might be something +dnl wrong with the CC or CFLAGS settings, give a useful warning message +CROSS_COMPILING= +if test "$cross_compiling" = yes; then + AC_MSG_RESULT([cannot compile a simple program; if not cross compiling check CC and CFLAGS]) + CROSS_COMPILING=1 +fi +AC_SUBST(CROSS_COMPILING) + +dnl gcc-cpp has the wonderful -MM option to produce nicer dependencies. +dnl But gcc 3.1 changed the meaning! See near the end. +test "$GCC" = yes && CPP_MM=M; AC_SUBST(CPP_MM) + +if test -f ./toolcheck; then + AC_MSG_CHECKING(for buggy tools) + sh ./toolcheck 1>&AS_MESSAGE_FD +fi + +OS_EXTRA_SRC=""; OS_EXTRA_OBJ="" + +dnl When cross-compiling set $vim_cv_uname_output, $vim_cv_uname_r_output and +dnl $vim_cv_uname_m_output to the desired value for the target system +AC_MSG_CHECKING(uname) +if test "x$vim_cv_uname_output" = "x" ; then + vim_cv_uname_output=`(uname) 2>/dev/null` + AC_MSG_RESULT($vim_cv_uname_output) +else + AC_MSG_RESULT([$vim_cv_uname_output (cached)]) +fi + +AC_MSG_CHECKING(uname -r) +if test "x$vim_cv_uname_r_output" = "x" ; then + vim_cv_uname_r_output=`(uname -r) 2>/dev/null` + AC_MSG_RESULT($vim_cv_uname_r_output) +else + AC_MSG_RESULT([$vim_cv_uname_r_output (cached)]) +fi + +AC_MSG_CHECKING(uname -m) +if test "x$vim_cv_uname_m_output" = "x" ; then + vim_cv_uname_m_output=`(uname -m) 2>/dev/null` + AC_MSG_RESULT($vim_cv_uname_m_output) +else + AC_MSG_RESULT([$vim_cv_uname_m_output (cached)]) +fi + +AC_MSG_CHECKING(for Haiku) +case $vim_cv_uname_output in + Haiku) HAIKU=yes; AC_MSG_RESULT(yes);; + *) HAIKU=no; AC_MSG_RESULT(no);; +esac + +dnl If QNX is found, assume we don't want to use Xphoton +dnl unless it was specifically asked for (--with-x) +AC_MSG_CHECKING(for QNX) +case $vim_cv_uname_output in + QNX) OS_EXTRA_SRC=os_qnx.c; OS_EXTRA_OBJ=objects/os_qnx.o + test -z "$with_x" && with_x=no + QNX=yes; AC_MSG_RESULT(yes);; + *) QNX=no; AC_MSG_RESULT(no);; +esac + +dnl Check for Darwin and MacOS X +dnl We do a check for MacOS X in the very beginning because there +dnl are a lot of other things we need to change besides GUI stuff +AC_MSG_CHECKING([for Darwin (Mac OS X)]) +if test "$vim_cv_uname_output" = Darwin; then + AC_MSG_RESULT(yes) + MACOS_X=yes + CPPFLAGS="$CPPFLAGS -DMACOS_X" + + AC_MSG_CHECKING(--disable-darwin argument) + AC_ARG_ENABLE(darwin, + [ --disable-darwin Disable Darwin (Mac OS X) support.], + , [enable_darwin="yes"]) + if test "$enable_darwin" = "yes"; then + AC_MSG_RESULT(no) + AC_MSG_CHECKING(if Darwin files are there) + if test -f os_macosx.m; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT([no, Darwin support disabled]) + enable_darwin=no + fi + else + AC_MSG_RESULT([yes, Darwin support excluded]) + fi + + AC_MSG_CHECKING(--with-mac-arch argument) + AC_ARG_WITH(mac-arch, [ --with-mac-arch=ARCH current, intel, ppc or both], + MACARCH="$withval"; AC_MSG_RESULT($MACARCH), + MACARCH="current"; AC_MSG_RESULT(defaulting to $MACARCH)) + + AC_MSG_CHECKING(--with-developer-dir argument) + AC_ARG_WITH(developer-dir, [ --with-developer-dir=PATH use PATH as location for Xcode developer tools], + DEVELOPER_DIR="$withval"; AC_MSG_RESULT($DEVELOPER_DIR), + AC_MSG_RESULT(not present)) + + if test "x$DEVELOPER_DIR" = "x"; then + AC_PATH_PROG(XCODE_SELECT, xcode-select) + if test "x$XCODE_SELECT" != "x"; then + AC_MSG_CHECKING(for developer dir using xcode-select) + DEVELOPER_DIR=`$XCODE_SELECT -print-path` + AC_MSG_RESULT([$DEVELOPER_DIR]) + else + DEVELOPER_DIR=/Developer + fi + fi + + if test "x$MACARCH" = "xboth"; then + AC_MSG_CHECKING(for 10.4 universal SDK) + dnl There is a terrible inconsistency (but we appear to get away with it): + dnl $CFLAGS uses the 10.4u SDK library for the headers, while $CPPFLAGS + dnl doesn't, because "gcc -E" doesn't grok it. That means the configure + dnl tests using the preprocessor are actually done with the wrong header + dnl files. $LDFLAGS is set at the end, because configure uses it together + dnl with $CFLAGS and we can only have one -sysroot argument. + save_cppflags="$CPPFLAGS" + save_cflags="$CFLAGS" + save_ldflags="$LDFLAGS" + CFLAGS="$CFLAGS -isysroot $DEVELOPER_DIR/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" + AC_LINK_IFELSE([AC_LANG_PROGRAM([ ], [ ])], + AC_MSG_RESULT(found, will make universal binary), + + AC_MSG_RESULT(not found) + CFLAGS="$save_cflags" + AC_MSG_CHECKING(if Intel architecture is supported) + CPPFLAGS="$CPPFLAGS -arch i386" + LDFLAGS="$save_ldflags -arch i386" + AC_LINK_IFELSE([AC_LANG_PROGRAM([ ], [ ])], + AC_MSG_RESULT(yes); MACARCH="intel", + AC_MSG_RESULT(no, using PowerPC) + MACARCH="ppc" + CPPFLAGS="$save_cppflags -arch ppc" + LDFLAGS="$save_ldflags -arch ppc")) + elif test "x$MACARCH" = "xintel"; then + CPPFLAGS="$CPPFLAGS -arch intel" + LDFLAGS="$LDFLAGS -arch intel" + elif test "x$MACARCH" = "xppc"; then + CPPFLAGS="$CPPFLAGS -arch ppc" + LDFLAGS="$LDFLAGS -arch ppc" + fi + + if test "$enable_darwin" = "yes"; then + MACOS_X_DARWIN=yes + OS_EXTRA_SRC="os_macosx.m os_mac_conv.c"; + OS_EXTRA_OBJ="objects/os_macosx.o objects/os_mac_conv.o" + dnl os_macosx.m implements timer_create() and friends + AC_DEFINE(HAVE_TIMER_CREATE) + dnl TODO: use -arch i386 on Intel machines + dnl Removed -no-cpp-precomp, only for very old compilers. + CPPFLAGS="$CPPFLAGS -DMACOS_X_DARWIN" + + dnl Assume we don't want X11 unless it was specifically asked for + dnl (--with-x) or Motif or GTK GUI is used. + if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xgtk2 -a "X$enable_gui" != Xgtk3; then + with_x=no + fi + fi + + dnl Avoid a bug with -O2 with gcc 4.0.1. Symptom: malloc() reports double + dnl free. This happens in expand_filename(), because the optimizer swaps + dnl two blocks of code, both using "repl", that can't be swapped. + if test "$MACARCH" = "intel" -o "$MACARCH" = "both"; then + CFLAGS=`echo "$CFLAGS" | sed 's/-O[[23456789]]/-Oz/'` + fi + +else + AC_MSG_RESULT(no) +fi + +dnl Mac OS X 10.9+ no longer include AvailabilityMacros.h in Carbon +dnl so we need to include it to have access to version macros. +AC_CHECK_HEADERS(AvailabilityMacros.h) +# 10.5 and earlier lack dispatch +AC_CHECK_HEADERS(dispatch/dispatch.h) + +AC_SUBST(OS_EXTRA_SRC) +AC_SUBST(OS_EXTRA_OBJ) + +dnl Add /usr/local/lib to $LDFLAGS and /usr/local/include to CFLAGS. +dnl Only when the directory exists and it wasn't there yet. +dnl For gcc don't do this when it is already in the default search path. +dnl Skip all of this when cross-compiling. +if test "$cross_compiling" = no; then + AC_MSG_CHECKING(--with-local-dir argument) + have_local_include='' + have_local_lib='' + AC_ARG_WITH([local-dir], [ --with-local-dir=PATH search PATH instead of /usr/local for local libraries. + --without-local-dir do not search /usr/local for local libraries.], [ + local_dir="$withval" + case "$withval" in + */*) ;; + no) + # avoid adding local dir to LDFLAGS and CPPFLAGS + have_local_include=yes + have_local_lib=yes + ;; + *) AC_MSG_ERROR(must pass path argument to --with-local-dir) ;; + esac + AC_MSG_RESULT($local_dir) + ], [ + local_dir=/usr/local + AC_MSG_RESULT(Defaulting to $local_dir) + ]) + if test "$GCC" = yes -a "$local_dir" != no; then + echo 'void f(){}' > conftest.c + dnl Removed -no-cpp-precomp, only needed for OS X 10.2 (Ben Fowler) + have_local_include=`${CC-cc} -c -v conftest.c 2>&1 | grep "${local_dir}/include"` + have_local_lib=`${CC-cc} -c -v conftest.c 2>&1 | grep "${local_dir}/lib"` + rm -f conftest.c conftest.o + fi + if test -z "$have_local_lib" -a -d "${local_dir}/lib"; then + tt=`echo "$LDFLAGS" | sed -e "s+-L${local_dir}/lib ++g" -e "s+-L${local_dir}/lib$++g"` + if test "$tt" = "$LDFLAGS"; then + LDFLAGS="$LDFLAGS -L${local_dir}/lib" + fi + fi + if test -z "$have_local_include" -a -d "${local_dir}/include"; then + tt=`echo "$CPPFLAGS" | sed -e "s+-I${local_dir}/include ++g" -e "s+-I${local_dir}/include$++g"` + if test "$tt" = "$CPPFLAGS"; then + CPPFLAGS="$CPPFLAGS -I${local_dir}/include" + fi + fi +fi + +AC_MSG_CHECKING(--with-vim-name argument) +AC_ARG_WITH(vim-name, [ --with-vim-name=NAME what to call the Vim executable], + VIMNAME="$withval"; AC_MSG_RESULT($VIMNAME), + VIMNAME="vim"; AC_MSG_RESULT(Defaulting to $VIMNAME)) +AC_SUBST(VIMNAME) +AC_MSG_CHECKING(--with-ex-name argument) +AC_ARG_WITH(ex-name, [ --with-ex-name=NAME what to call the Ex executable], + EXNAME="$withval"; AC_MSG_RESULT($EXNAME), + EXNAME="ex"; AC_MSG_RESULT(Defaulting to ex)) +AC_SUBST(EXNAME) +AC_MSG_CHECKING(--with-view-name argument) +AC_ARG_WITH(view-name, [ --with-view-name=NAME what to call the View executable], + VIEWNAME="$withval"; AC_MSG_RESULT($VIEWNAME), + VIEWNAME="view"; AC_MSG_RESULT(Defaulting to view)) +AC_SUBST(VIEWNAME) + +AC_MSG_CHECKING(--with-global-runtime argument) +AC_ARG_WITH(global-runtime, [ --with-global-runtime=DIR global runtime directory in 'runtimepath', comma-separated for multiple directories], + RUNTIME_GLOBAL="$withval"; AC_MSG_RESULT($withval), + AC_MSG_RESULT(no)) + +if test "X$RUNTIME_GLOBAL" != "X"; then + RUNTIME_GLOBAL_AFTER=$(printf -- "$RUNTIME_GLOBAL\\n" | $AWK -F, 'BEGIN { comma=0 } { for (i = NF; i > 0; i--) { if (comma) { printf ",%s/after", $i } else { printf "%s/after", $i; comma=1 } } } END { printf "\n" }') + AC_DEFINE_UNQUOTED(RUNTIME_GLOBAL, "$RUNTIME_GLOBAL") + AC_DEFINE_UNQUOTED(RUNTIME_GLOBAL_AFTER, "$RUNTIME_GLOBAL_AFTER") +fi + +AC_MSG_CHECKING(--with-modified-by argument) +AC_ARG_WITH(modified-by, [ --with-modified-by=NAME name of who modified a release version], + AC_MSG_RESULT($withval); AC_DEFINE_UNQUOTED(MODIFIED_BY, "$withval"), + AC_MSG_RESULT(no)) + +dnl Check for EBCDIC stolen from the LYNX port to z/OS Unix +AC_MSG_CHECKING(if character set is EBCDIC) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ ], +[ /* TryCompile function for CharSet. + Treat any failure as ASCII for compatibility with existing art. + Use compile-time rather than run-time tests for cross-compiler + tolerance. */ +#if '0'!=240 +make an error "Character set is not EBCDIC" +#endif ])], +[ # TryCompile action if true +cf_cv_ebcdic=yes ], +[ # TryCompile action if false +cf_cv_ebcdic=no]) +# end of TryCompile ]) +# end of CacheVal CvEbcdic +AC_MSG_RESULT($cf_cv_ebcdic) +case "$cf_cv_ebcdic" in #(vi + yes) AC_DEFINE(EBCDIC) + line_break='"\\n"' + ;; + *) line_break='"\\012"';; +esac +AC_SUBST(line_break) + +if test "$cf_cv_ebcdic" = "yes"; then +dnl If we have EBCDIC we most likely have z/OS Unix, let's test it! +AC_MSG_CHECKING(for z/OS Unix) +case $vim_cv_uname_output in + OS/390) zOSUnix="yes"; + dnl If using cc the environment variable _CC_CCMODE must be + dnl set to "1", so that some compiler extensions are enabled. + dnl If using c89 the environment variable is named _CC_C89MODE. + dnl Note: compile with c89 never tested. + if test "$CC" = "cc"; then + ccm="$_CC_CCMODE" + ccn="CC" + else + if test "$CC" = "c89"; then + ccm="$_CC_C89MODE" + ccn="C89" + else + ccm=1 + fi + fi + if test "$ccm" != "1"; then + echo "" + echo "------------------------------------------" + echo " On z/OS Unix, the environment variable" + echo " _CC_${ccn}MODE must be set to \"1\"!" + echo " Do:" + echo " export _CC_${ccn}MODE=1" + echo " and then call configure again." + echo "------------------------------------------" + exit 1 + fi + # Set CFLAGS for configure process. + # This will be reset later for config.mk. + # Use haltonmsg to force error for missing H files. + CFLAGS="$CFLAGS -D_ALL_SOURCE -Wc,float(ieee),haltonmsg(3296)"; + LDFLAGS="$LDFLAGS -Wl,EDIT=NO" + AC_MSG_RESULT(yes) + ;; + *) zOSUnix="no"; + AC_MSG_RESULT(no) + ;; +esac +fi + +dnl Set QUOTESED. Needs additional backslashes on zOS +if test "$zOSUnix" = "yes"; then + QUOTESED="sed -e 's/[[\\\\\"]]/\\\\\\\\&/g' -e 's/\\\\\\\\\"/\"/' -e 's/\\\\\\\\\";\$\$/\";/' -e 's/ */ /g'" +else + QUOTESED="sed -e 's/[[\\\\\"]]/\\\\&/g' -e 's/\\\\\"/\"/' -e 's/\\\\\";\$\$/\";/' -e 's/ */ /g'" +fi +AC_SUBST(QUOTESED) + + +dnl Link with -lsmack for Smack stuff; if not found +AC_MSG_CHECKING(--disable-smack argument) +AC_ARG_ENABLE(smack, + [ --disable-smack Do not check for Smack support.], + , enable_smack="yes") +if test "$enable_smack" = "yes"; then + AC_MSG_RESULT(no) + AC_CHECK_HEADER([linux/xattr.h], true, enable_smack="no") +else + AC_MSG_RESULT(yes) +fi +if test "$enable_smack" = "yes"; then + AC_CHECK_HEADER([attr/xattr.h], true, enable_smack="no") +fi +if test "$enable_smack" = "yes"; then + AC_MSG_CHECKING(for XATTR_NAME_SMACKEXEC in linux/xattr.h) + AC_EGREP_CPP(XATTR_NAME_SMACKEXEC, [#include ], + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no); enable_smack="no") +fi +if test "$enable_smack" = "yes"; then + AC_CHECK_LIB(attr, setxattr, + [LIBS="$LIBS -lattr" + found_smack="yes" + AC_DEFINE(HAVE_SMACK)]) +fi + +dnl When smack was found don't search for SELinux +if test "x$found_smack" = "x"; then + dnl Link with -lselinux for SELinux stuff; if not found + AC_MSG_CHECKING(--disable-selinux argument) + AC_ARG_ENABLE(selinux, + [ --disable-selinux Do not check for SELinux support.], + , enable_selinux="yes") + if test "$enable_selinux" = "yes"; then + AC_MSG_RESULT(no) + AC_CHECK_LIB(selinux, is_selinux_enabled, + [AC_CHECK_HEADER(selinux/selinux.h, + [LIBS="$LIBS -lselinux" + AC_DEFINE(HAVE_SELINUX)])]) + else + AC_MSG_RESULT(yes) + fi +fi + +dnl Check user requested features. + +AC_MSG_CHECKING(--with-features argument) +AC_ARG_WITH(features, [ --with-features=TYPE tiny, normal or huge (default: huge)], + features="$withval"; AC_MSG_RESULT($features), + features="huge"; AC_MSG_RESULT(Defaulting to huge)) + +dnl "small" is supported for backwards compatibility, now an alias for "tiny" +dnl "big" is supported for backwards compatibility, now an alias for "normal" +case "$features" in + small) features="tiny" ;; + big) features="normal" ;; +esac + +dovimdiff="" +dogvimdiff="" +case "$features" in + tiny) AC_DEFINE(FEAT_TINY) ;; + normal) AC_DEFINE(FEAT_NORMAL) dovimdiff="installvimdiff"; + dogvimdiff="installgvimdiff" ;; + huge) AC_DEFINE(FEAT_HUGE) dovimdiff="installvimdiff"; + dogvimdiff="installgvimdiff" ;; + *) AC_MSG_RESULT([Sorry, $features is not supported]) ;; +esac + +AC_SUBST(dovimdiff) +AC_SUBST(dogvimdiff) + +if test "x$features" = "xtiny"; then + has_eval=no +else + has_eval=yes +fi + +AC_MSG_CHECKING(--with-compiledby argument) +AC_ARG_WITH(compiledby, [ --with-compiledby=NAME name to show in :version message], + compiledby="$withval"; AC_MSG_RESULT($withval), + compiledby=""; AC_MSG_RESULT(no)) +AC_SUBST(compiledby) + +AC_MSG_CHECKING(--disable-xsmp argument) +AC_ARG_ENABLE(xsmp, + [ --disable-xsmp Disable XSMP session management], + , enable_xsmp="yes") + +if test "$enable_xsmp" = "yes"; then + AC_MSG_RESULT(no) + AC_MSG_CHECKING(--disable-xsmp-interact argument) + AC_ARG_ENABLE(xsmp-interact, + [ --disable-xsmp-interact Disable XSMP interaction], + , enable_xsmp_interact="yes") + if test "$enable_xsmp_interact" = "yes"; then + AC_MSG_RESULT(no) + AC_DEFINE(USE_XSMP_INTERACT) + else + AC_MSG_RESULT(yes) + fi +else + AC_MSG_RESULT(yes) +fi + +AC_MSG_CHECKING([diff feature]) +if test "x$features" = "xtiny"; then + AC_MSG_RESULT([disabled in $features version]) +else + AC_MSG_RESULT(enabled) + AC_DEFINE(FEAT_DIFF) + XDIFF_OBJS_USED="\$(XDIFF_OBJS)" + AC_SUBST(XDIFF_OBJS_USED) +fi + +dnl Check for Lua feature. +AC_MSG_CHECKING(--enable-luainterp argument) +AC_ARG_ENABLE(luainterp, + [ --enable-luainterp[=OPTS] Include Lua interpreter. [default=no] [OPTS=no/yes/dynamic]], , + [enable_luainterp="no"]) +AC_MSG_RESULT($enable_luainterp) + +if test "$enable_luainterp" = "yes" -o "$enable_luainterp" = "dynamic"; then + if test "$has_eval" = "no"; then + AC_MSG_ERROR([cannot use Lua with tiny features]) + fi + + dnl -- find the lua executable + AC_SUBST(vi_cv_path_lua) + + AC_MSG_CHECKING(--with-lua-prefix argument) + AC_ARG_WITH(lua_prefix, + [ --with-lua-prefix=PFX Prefix where Lua is installed.], + with_lua_prefix="$withval"; AC_MSG_RESULT($with_lua_prefix), + with_lua_prefix="";AC_MSG_RESULT(no)) + + if test "X$with_lua_prefix" != "X"; then + vi_cv_path_lua_pfx="$with_lua_prefix" + else + AC_MSG_CHECKING(LUA_PREFIX environment var) + if test "X$LUA_PREFIX" != "X"; then + AC_MSG_RESULT("$LUA_PREFIX") + vi_cv_path_lua_pfx="$LUA_PREFIX" + else + AC_MSG_RESULT([not set, default to /usr]) + vi_cv_path_lua_pfx="/usr" + fi + fi + + AC_MSG_CHECKING(--with-luajit) + AC_ARG_WITH(luajit, + [ --with-luajit Link with LuaJIT instead of Lua.], + [vi_cv_with_luajit="$withval"], + [vi_cv_with_luajit="no"]) + AC_MSG_RESULT($vi_cv_with_luajit) + + LUA_INC= + if test "X$vi_cv_path_lua_pfx" != "X"; then + if test "x$vi_cv_with_luajit" != "xno"; then + dnl -- try to find LuaJIT executable + AC_PATH_PROG(vi_cv_path_luajit, luajit) + if test "X$vi_cv_path_luajit" != "X"; then + dnl -- find LuaJIT version + AC_CACHE_CHECK(LuaJIT version, vi_cv_version_luajit, + [ vi_cv_version_luajit=`${vi_cv_path_luajit} -v 2>&1 | sed 's/LuaJIT \([[0-9.]]*\)\.[[0-9]]\(-[[a-z0-9]]*\)* .*/\1/'` ]) + AC_CACHE_CHECK(Lua version of LuaJIT, vi_cv_version_lua_luajit, + [ vi_cv_version_lua_luajit=`${vi_cv_path_luajit} -e "print(_VERSION)" | sed 's/.* //'` ]) + vi_cv_path_lua="$vi_cv_path_luajit" + vi_cv_version_lua="$vi_cv_version_lua_luajit" + fi + else + dnl -- try to find Lua executable + AC_PATH_PROG(vi_cv_path_plain_lua, lua) + if test "X$vi_cv_path_plain_lua" != "X"; then + dnl -- find Lua version + AC_CACHE_CHECK(Lua version, vi_cv_version_plain_lua, + [ vi_cv_version_plain_lua=`${vi_cv_path_plain_lua} -e "print(_VERSION)" | sed 's/.* //'` ]) + fi + vi_cv_path_lua="$vi_cv_path_plain_lua" + vi_cv_version_lua="$vi_cv_version_plain_lua" + fi + if test "x$vi_cv_with_luajit" != "xno" && test "X$vi_cv_version_luajit" != "X"; then + AC_MSG_CHECKING(if lua.h can be found in $vi_cv_path_lua_pfx/include/luajit-$vi_cv_version_luajit) + if test -f "$vi_cv_path_lua_pfx/include/luajit-$vi_cv_version_luajit/lua.h"; then + AC_MSG_RESULT(yes) + LUA_INC=/luajit-$vi_cv_version_luajit + fi + fi + if test "X$LUA_INC" = "X"; then + AC_MSG_CHECKING(if lua.h can be found in $vi_cv_path_lua_pfx/include) + if test -f "$vi_cv_path_lua_pfx/include/lua.h"; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + AC_MSG_CHECKING(if lua.h can be found in $vi_cv_path_lua_pfx/include/lua$vi_cv_version_lua) + if test -f "$vi_cv_path_lua_pfx/include/lua$vi_cv_version_lua/lua.h"; then + AC_MSG_RESULT(yes) + LUA_INC=/lua$vi_cv_version_lua + else + AC_MSG_RESULT(no) + + # Detect moonjit: + # https://groups.google.com/forum/#!topic/vim_use/O0vek60WuTk + lua_suf=/moonjit-2.3 + inc_path="$vi_cv_path_lua_pfx/include" + for dir in "$inc_path"/moonjit-[[0-9]]* ; do + if test -d "$dir" ; then + lua_suf=`basename "$dir"` + lua_suf="/$lua_suf" + break + fi + done + AC_MSG_CHECKING(if lua.h can be found in $inc_path$lua_suf) + if test -f "$inc_path$lua_suf/lua.h"; then + AC_MSG_RESULT(yes) + LUA_INC=$lua_suf + else + AC_MSG_RESULT(no) + vi_cv_path_lua_pfx= + fi + fi + fi + fi + fi + + if test "X$vi_cv_path_lua_pfx" != "X"; then + if test "x$vi_cv_with_luajit" != "xno"; then + multiarch=`dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null` + if test "X$multiarch" != "X"; then + lib_multiarch="lib/${multiarch}" + else + lib_multiarch="lib" + fi + if test "X$vi_cv_version_lua" = "X"; then + LUA_LIBS="-L${vi_cv_path_lua_pfx}/${lib_multiarch} -lluajit" + else + LUA_LIBS="-L${vi_cv_path_lua_pfx}/${lib_multiarch} -lluajit-$vi_cv_version_lua" + fi + else + if test "X$LUA_INC" != "X"; then + dnl Test alternate location using version + LUA_LIBS="-L${vi_cv_path_lua_pfx}/lib -llua$vi_cv_version_lua" + else + LUA_LIBS="-L${vi_cv_path_lua_pfx}/lib -llua" + fi + fi + if test "$enable_luainterp" = "dynamic"; then + lua_ok="yes" + else + AC_MSG_CHECKING([if link with ${LUA_LIBS} is sane]) + libs_save=$LIBS + LIBS="$LIBS $LUA_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ ])], + AC_MSG_RESULT(yes); lua_ok="yes", + AC_MSG_RESULT(no); lua_ok="no"; LUA_LIBS="") + LIBS=$libs_save + fi + if test "x$lua_ok" = "xyes"; then + LUA_CFLAGS="-I${vi_cv_path_lua_pfx}/include${LUA_INC}" + LUA_SRC="if_lua.c" + LUA_OBJ="objects/if_lua.o" + LUA_PRO="if_lua.pro" + AC_DEFINE(FEAT_LUA) + fi + if test "$enable_luainterp" = "dynamic"; then + if test "x$vi_cv_with_luajit" != "xno"; then + luajit="jit" + fi + if test -f "${vi_cv_path_lua_pfx}/bin/cyglua-${vi_cv_version_lua}.dll"; then + vi_cv_dll_name_lua="cyglua-${vi_cv_version_lua}.dll" + else + if test "x$MACOS_X" = "xyes"; then + ext="dylib" + indexes="" + else + ext="so" + indexes=".0 .1 .2 .3 .4 .5 .6 .7 .8 .9" + multiarch=`dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null` + if test "X$multiarch" != "X"; then + lib_multiarch="lib/${multiarch}" + fi + fi + dnl Determine the sover for the current version, but fallback to + dnl liblua${vi_cv_version_lua}.so if no sover-versioned file is found. + AC_MSG_CHECKING(if liblua${luajit}*.${ext}* can be found in $vi_cv_path_lua_pfx) + for subdir in "${lib_multiarch}" lib64 lib; do + if test -z "$subdir"; then + continue + fi + for sover in "${vi_cv_version_lua}.${ext}" "-${vi_cv_version_lua}.${ext}" \ + ".${vi_cv_version_lua}.${ext}" ".${ext}.${vi_cv_version_lua}"; do + for i in $indexes ""; do + if test -f "${vi_cv_path_lua_pfx}/${subdir}/liblua${luajit}${sover}$i"; then + sover2="$i" + break 3 + fi + done + done + sover="" + done + if test "X$sover" = "X"; then + AC_MSG_RESULT(no) + lua_ok="no" + vi_cv_dll_name_lua="liblua${luajit}.${ext}" + else + AC_MSG_RESULT(yes) + lua_ok="yes" + vi_cv_dll_name_lua="liblua${luajit}${sover}$sover2" + fi + fi + AC_DEFINE(DYNAMIC_LUA) + LUA_LIBS="" + LUA_CFLAGS="-DDYNAMIC_LUA_DLL=\\\"${vi_cv_dll_name_lua}\\\" $LUA_CFLAGS" + fi + if test "X$LUA_CFLAGS$LUA_LIBS" != "X" && \ + test "x$MACOS_X" = "xyes" && test "x$vi_cv_with_luajit" != "xno" && \ + test "$vim_cv_uname_m_output" = "x86_64"; then + dnl OSX/x64 requires these flags. See http://luajit.org/install.html + LUA_LIBS="-pagezero_size 10000 -image_base 100000000 $LUA_LIBS" + fi + fi + if test "$fail_if_missing" = "yes" -a "$lua_ok" != "yes"; then + AC_MSG_ERROR([could not configure lua]) + fi + AC_SUBST(LUA_SRC) + AC_SUBST(LUA_OBJ) + AC_SUBST(LUA_PRO) + AC_SUBST(LUA_LIBS) + AC_SUBST(LUA_CFLAGS) + AC_SUBST(LUA_CFLAGS_EXTRA) +fi + + +dnl Check for MzScheme feature. +AC_MSG_CHECKING(--enable-mzschemeinterp argument) +AC_ARG_ENABLE(mzschemeinterp, + [ --enable-mzschemeinterp Include MzScheme interpreter.], , + [enable_mzschemeinterp="no"]) +AC_MSG_RESULT($enable_mzschemeinterp) + +if test "$enable_mzschemeinterp" = "yes"; then + dnl -- find the mzscheme executable + AC_SUBST(vi_cv_path_mzscheme) + + AC_MSG_CHECKING(--with-plthome argument) + AC_ARG_WITH(plthome, + [ --with-plthome=PLTHOME Use PLTHOME.], + with_plthome="$withval"; AC_MSG_RESULT($with_plthome), + with_plthome="";AC_MSG_RESULT("no")) + + if test "X$with_plthome" != "X"; then + vi_cv_path_mzscheme_pfx="$with_plthome" + vi_cv_path_mzscheme="${vi_cv_path_mzscheme_pfx}/bin/mzscheme" + else + AC_MSG_CHECKING(PLTHOME environment var) + if test "X$PLTHOME" != "X"; then + AC_MSG_RESULT("$PLTHOME") + vi_cv_path_mzscheme_pfx="$PLTHOME" + vi_cv_path_mzscheme="${vi_cv_path_mzscheme_pfx}/bin/mzscheme" + else + AC_MSG_RESULT(not set) + dnl -- try to find MzScheme executable + AC_PATH_PROG(vi_cv_path_mzscheme, mzscheme) + + dnl resolve symbolic link, the executable is often elsewhere and there + dnl are no links for the include files. + if test "X$vi_cv_path_mzscheme" != "X"; then + lsout=`ls -l $vi_cv_path_mzscheme` + if echo "$lsout" | grep -e '->' >/dev/null 2>/dev/null; then + vi_cv_path_mzscheme=`echo "$lsout" | sed 's/.*-> \(.*\)/\1/'` + fi + fi + + if test "X$vi_cv_path_mzscheme" != "X"; then + dnl -- find where MzScheme thinks it was installed + AC_CACHE_CHECK(MzScheme install prefix,vi_cv_path_mzscheme_pfx, + dnl different versions of MzScheme differ in command line processing + dnl use universal approach + echo "(display (simplify-path \ + (build-path (call-with-values \ + (lambda () (split-path (find-system-path (quote exec-file)))) \ + (lambda (base name must-be-dir?) base)) (quote up))))" > mzdirs.scm + dnl Remove a trailing slash + [ vi_cv_path_mzscheme_pfx=`${vi_cv_path_mzscheme} -r mzdirs.scm | \ + sed -e 's+/$++'` ]) + rm -f mzdirs.scm + fi + fi + fi + + if test "X$vi_cv_path_mzscheme_pfx" != "X"; then + AC_MSG_CHECKING(for racket include directory) + SCHEME_INC=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-include-dir))) (when (path? p) (display p)))'` + if test "X$SCHEME_INC" != "X"; then + AC_MSG_RESULT(${SCHEME_INC}) + else + AC_MSG_RESULT(not found) + AC_MSG_CHECKING(if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include) + if test -f "$vi_cv_path_mzscheme_pfx/include/scheme.h"; then + SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + AC_MSG_CHECKING(if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/plt) + if test -f "$vi_cv_path_mzscheme_pfx/include/plt/scheme.h"; then + AC_MSG_RESULT(yes) + SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include/plt + else + AC_MSG_RESULT(no) + AC_MSG_CHECKING(if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/racket) + if test -f "$vi_cv_path_mzscheme_pfx/include/racket/scheme.h"; then + AC_MSG_RESULT(yes) + SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include/racket + else + AC_MSG_RESULT(no) + AC_MSG_CHECKING(if scheme.h can be found in /usr/include/plt/) + if test -f /usr/include/plt/scheme.h; then + AC_MSG_RESULT(yes) + SCHEME_INC=/usr/include/plt + else + AC_MSG_RESULT(no) + AC_MSG_CHECKING(if scheme.h can be found in /usr/include/racket/) + if test -f /usr/include/racket/scheme.h; then + AC_MSG_RESULT(yes) + SCHEME_INC=/usr/include/racket + else + AC_MSG_RESULT(no) + vi_cv_path_mzscheme_pfx= + fi + fi + fi + fi + fi + fi + fi + + if test "X$vi_cv_path_mzscheme_pfx" != "X"; then + + AC_MSG_CHECKING(for racket lib directory) + SCHEME_LIB=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-lib-dir))) (when (path? p) (display p)))'` + if test "X$SCHEME_LIB" != "X"; then + AC_MSG_RESULT(${SCHEME_LIB}) + else + AC_MSG_RESULT(not found) + fi + + for path in "${vi_cv_path_mzscheme_pfx}/lib" "${SCHEME_LIB}"; do + if test "X$path" != "X"; then + if test "x$MACOS_X" = "xyes"; then + MZSCHEME_LIBS="-framework Racket" + MZSCHEME_CFLAGS="-DMZ_PRECISE_GC" + elif test -f "${path}/libmzscheme3m.a"; then + MZSCHEME_LIBS="${path}/libmzscheme3m.a" + MZSCHEME_CFLAGS="-DMZ_PRECISE_GC" + elif test -f "${path}/libracket3m.a"; then + MZSCHEME_LIBS="${path}/libracket3m.a" + if test -f "${path}/librktio.a"; then + MZSCHEME_LIBS="${MZSCHEME_LIBS} ${path}/librktio.a" + fi + MZSCHEME_CFLAGS="-DMZ_PRECISE_GC" + elif test -f "${path}/libracket.a"; then + MZSCHEME_LIBS="${path}/libracket.a ${path}/libmzgc.a" + elif test -f "${path}/libmzscheme.a"; then + MZSCHEME_LIBS="${path}/libmzscheme.a ${path}/libmzgc.a" + else + dnl Using shared objects + if test -f "${path}/libmzscheme3m.so"; then + MZSCHEME_LIBS="-L${path} -lmzscheme3m" + MZSCHEME_CFLAGS="-DMZ_PRECISE_GC" + elif test -f "${path}/libracket3m.so"; then + MZSCHEME_LIBS="-L${path} -lracket3m" + MZSCHEME_CFLAGS="-DMZ_PRECISE_GC" + elif test -f "${path}/libracket.so"; then + MZSCHEME_LIBS="-L${path} -lracket -lmzgc" + else + dnl try next until last + if test "$path" != "$SCHEME_LIB"; then + continue + fi + MZSCHEME_LIBS="-L${path} -lmzscheme -lmzgc" + fi + if test "$GCC" = yes; then + dnl Make Vim remember the path to the library. For when it's not in + dnl $LD_LIBRARY_PATH. + MZSCHEME_LIBS="${MZSCHEME_LIBS} -Wl,-rpath -Wl,${path}" + elif test "$vim_cv_uname_output" = SunOS && + echo $vim_cv_uname_r_output | grep '^5' >/dev/null; then + MZSCHEME_LIBS="${MZSCHEME_LIBS} -R ${path}" + fi + fi + fi + if test "X$MZSCHEME_LIBS" != "X"; then + break + fi + done + + AC_MSG_CHECKING([if racket requires -pthread]) + if test "X$SCHEME_LIB" != "X" && $FGREP -e -pthread "$SCHEME_LIB/buildinfo" >/dev/null ; then + AC_MSG_RESULT(yes) + MZSCHEME_LIBS="${MZSCHEME_LIBS} -pthread" + MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -pthread" + else + AC_MSG_RESULT(no) + fi + + AC_MSG_CHECKING(for racket config directory) + SCHEME_CONFIGDIR=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-config-dir))) (when (path? p) (display p)))'` + if test "X$SCHEME_CONFIGDIR" != "X"; then + MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -DMZSCHEME_CONFIGDIR='\"${SCHEME_CONFIGDIR}\"'" + AC_MSG_RESULT(${SCHEME_CONFIGDIR}) + else + AC_MSG_RESULT(not found) + fi + + AC_MSG_CHECKING(for racket collects directory) + SCHEME_COLLECTS=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-collects-dir))) (when (path? p) (let-values (((base _1 _2) (split-path p))) (display base))))'` + if test "X$SCHEME_COLLECTS" = "X"; then + if test -d "$vi_cv_path_mzscheme_pfx/lib/plt/collects"; then + SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/lib/plt/ + else + if test -d "$vi_cv_path_mzscheme_pfx/lib/racket/collects"; then + SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/lib/racket/ + else + if test -d "$vi_cv_path_mzscheme_pfx/share/racket/collects"; then + SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/share/racket/ + else + if test -d "$vi_cv_path_mzscheme_pfx/collects"; then + SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/ + fi + fi + fi + fi + fi + if test "X$SCHEME_COLLECTS" != "X" ; then + AC_MSG_RESULT(${SCHEME_COLLECTS}) + else + AC_MSG_RESULT(not found) + fi + + AC_MSG_CHECKING(for mzscheme_base.c) + if test -f "${SCHEME_COLLECTS}collects/scheme/base.ss" ; then + MZSCHEME_EXTRA="mzscheme_base.c" + MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/mzc" + MZSCHEME_MOD="++lib scheme/base" + else + if test -f "${SCHEME_COLLECTS}collects/scheme/base.rkt" ; then + MZSCHEME_EXTRA="mzscheme_base.c" + MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/mzc" + MZSCHEME_MOD="++lib scheme/base" + else + if test -f "${SCHEME_COLLECTS}collects/racket/base.rkt" ; then + MZSCHEME_EXTRA="mzscheme_base.c" + MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/raco ctool" + MZSCHEME_MOD="" + fi + fi + fi + if test "X$MZSCHEME_EXTRA" != "X" ; then + dnl need to generate bytecode for MzScheme base + MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -DINCLUDE_MZSCHEME_BASE" + AC_MSG_RESULT(needed) + else + AC_MSG_RESULT(not needed) + fi + + dnl On Ubuntu this fixes "undefined reference to symbol 'ffi_type_void'". + AC_CHECK_LIB(ffi, ffi_type_void, [MZSCHEME_LIBS="$MZSCHEME_LIBS -lffi"]) + + MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -I${SCHEME_INC} \ + -DMZSCHEME_COLLECTS='\"${SCHEME_COLLECTS}collects\"'" + + dnl Test that we can compile a simple program with these CFLAGS and LIBS. + AC_MSG_CHECKING([if compile and link flags for MzScheme are sane]) + cflags_save=$CFLAGS + libs_save=$LIBS + CFLAGS="$CFLAGS $MZSCHEME_CFLAGS" + LIBS="$LIBS $MZSCHEME_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ ])], + AC_MSG_RESULT(yes); mzs_ok=yes, + AC_MSG_RESULT(no: MZSCHEME DISABLED); mzs_ok=no) + CFLAGS=$cflags_save + LIBS=$libs_save + if test $mzs_ok = yes; then + MZSCHEME_SRC="if_mzsch.c" + MZSCHEME_OBJ="objects/if_mzsch.o" + MZSCHEME_PRO="if_mzsch.pro" + AC_DEFINE(FEAT_MZSCHEME) + else + MZSCHEME_CFLAGS= + MZSCHEME_LIBS= + MZSCHEME_EXTRA= + MZSCHEME_MZC= + fi + fi + AC_SUBST(MZSCHEME_SRC) + AC_SUBST(MZSCHEME_OBJ) + AC_SUBST(MZSCHEME_PRO) + AC_SUBST(MZSCHEME_LIBS) + AC_SUBST(MZSCHEME_CFLAGS) + AC_SUBST(MZSCHEME_EXTRA) + AC_SUBST(MZSCHEME_MZC) +fi + + +AC_MSG_CHECKING(--enable-perlinterp argument) +AC_ARG_ENABLE(perlinterp, + [ --enable-perlinterp[=OPTS] Include Perl interpreter. [default=no] [OPTS=no/yes/dynamic]], , + [enable_perlinterp="no"]) +AC_MSG_RESULT($enable_perlinterp) +if test "$enable_perlinterp" = "yes" -o "$enable_perlinterp" = "dynamic"; then + if test "$has_eval" = "no"; then + AC_MSG_ERROR([cannot use Perl with tiny features]) + fi + AC_SUBST(vi_cv_path_perl) + AC_PATH_PROG(vi_cv_path_perl, perl) + if test "X$vi_cv_path_perl" != "X"; then + AC_MSG_CHECKING(Perl version) + if $vi_cv_path_perl -e 'require 5.003_01' >/dev/null 2>/dev/null; then + eval `$vi_cv_path_perl -V:usethreads` + eval `$vi_cv_path_perl -V:libperl` + if test "X$usethreads" = "XUNKNOWN" -o "X$usethreads" = "Xundef"; then + badthreads=no + else + if $vi_cv_path_perl -e 'require 5.6.0' >/dev/null 2>/dev/null; then + eval `$vi_cv_path_perl -V:use5005threads` + if test "X$use5005threads" = "XUNKNOWN" -o "X$use5005threads" = "Xundef"; then + badthreads=no + else + badthreads=yes + AC_MSG_RESULT(>>> Perl > 5.6 with 5.5 threads cannot be used <<<) + fi + else + badthreads=yes + AC_MSG_RESULT(>>> Perl 5.5 with threads cannot be used <<<) + fi + fi + if test $badthreads = no; then + AC_MSG_RESULT(OK) + eval `$vi_cv_path_perl -V:shrpenv` + if test "X$shrpenv" = "XUNKNOWN"; then # pre 5.003_04 + shrpenv="" + fi + vi_cv_perllib=`$vi_cv_path_perl -MConfig -e 'print $Config{privlibexp}'` + AC_SUBST(vi_cv_perllib) + vi_cv_perl_extutils=unknown_perl_extutils_path + for extutils_rel_path in ExtUtils vendor_perl/ExtUtils; do + xsubpp_path="$vi_cv_perllib/$extutils_rel_path/xsubpp" + if test -f "$xsubpp_path"; then + vi_cv_perl_xsubpp="$xsubpp_path" + fi + done + AC_SUBST(vi_cv_perl_xsubpp) + dnl Remove "-fno-something", it breaks using cproto. + dnl Remove "-fdebug-prefix-map", it isn't supported by clang. + dnl Remove "FORTIFY_SOURCE", it will be defined twice. + dnl remove -pipe and -Wxxx, it confuses cproto + perlcppflags=`$vi_cv_path_perl -Mlib=$srcdir -MExtUtils::Embed \ + -e 'ccflags;perl_inc;print"\n"' | sed -e 's/-fno[[^ ]]*//' \ + -e 's/-fdebug-prefix-map[[^ ]]*//g' \ + -e 's/-pipe //' \ + -e 's/-W[[^ ]]*//g' \ + -e 's/-D_FORTIFY_SOURCE=.//g'` + dnl Remove "-lc", it breaks on FreeBSD when using "-pthread". + perllibs=`cd $srcdir; $vi_cv_path_perl -MExtUtils::Embed -e 'ldopts' | \ + sed -e '/Warning/d' -e '/Note (probably harmless)/d' \ + -e 's/-bE:perl.exp//' -e 's/-lc //'` + dnl Don't add perl lib to $LIBS: if it's not in LD_LIBRARY_PATH + dnl a test in configure may fail because of that. + perlldflags=`cd $srcdir; $vi_cv_path_perl -MExtUtils::Embed \ + -e 'ccdlflags' | sed -e 's/-bE:perl.exp//'` + + dnl check that compiling a simple program still works with the flags + dnl added for Perl. + AC_MSG_CHECKING([if compile and link flags for Perl are sane]) + cflags_save=$CFLAGS + libs_save=$LIBS + ldflags_save=$LDFLAGS + CFLAGS="$CFLAGS $perlcppflags" + LIBS="$LIBS $perllibs" + perlldflags=`echo "$perlldflags" | sed -e 's/^ *//g'` + LDFLAGS="$perlldflags $LDFLAGS" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ ])], + AC_MSG_RESULT(yes); perl_ok=yes, + AC_MSG_RESULT(no: PERL DISABLED); perl_ok=no) + CFLAGS=$cflags_save + LIBS=$libs_save + LDFLAGS=$ldflags_save + if test $perl_ok = yes; then + if test "X$perlcppflags" != "X"; then + PERL_CFLAGS=$perlcppflags + fi + if test "X$perlldflags" != "X"; then + if test "X`echo \"$LDFLAGS\" | $FGREP -e \"$perlldflags\"`" = "X"; then + LDFLAGS="$perlldflags $LDFLAGS" + fi + fi + PERL_LIBS=$perllibs + PERL_SRC="auto/if_perl.c if_perlsfio.c" + PERL_OBJ="objects/if_perl.o objects/if_perlsfio.o" + PERL_PRO="if_perl.pro if_perlsfio.pro" + AC_DEFINE(FEAT_PERL) + fi + fi + else + AC_MSG_RESULT(>>> too old; need Perl version 5.003_01 or later <<<) + fi + fi + + if test "x$MACOS_X" = "xyes"; then + dnl Mac OS X 10.2 or later + dir=/System/Library/Perl + darwindir=$dir/darwin + if test -d $darwindir; then + PERL=/usr/bin/perl + else + dnl Mac OS X 10.3 + dir=/System/Library/Perl/5.8.1 + darwindir=$dir/darwin-thread-multi-2level + if test -d $darwindir; then + PERL=/usr/bin/perl + fi + fi + if test -n "$PERL"; then + PERL_DIR="$dir" + PERL_CFLAGS="-DFEAT_PERL -I$darwindir/CORE" + PERL_OBJ="objects/if_perl.o objects/if_perlsfio.o $darwindir/auto/DynaLoader/DynaLoader.a" + PERL_LIBS="-L$darwindir/CORE -lperl" + fi + dnl Perl on Mac OS X 10.5 adds "-arch" flags but these should only + dnl be included if requested by passing --with-mac-arch to + dnl configure, so strip these flags first (if present) + PERL_LIBS=`echo "$PERL_LIBS" | sed -e 's/-arch\ ppc//' -e 's/-arch\ i386//' -e 's/-arch\ x86_64//'` + PERL_CFLAGS=`echo "$PERL_CFLAGS" | sed -e 's/-arch\ ppc//' -e 's/-arch\ i386//' -e 's/-arch\ x86_64//'` + fi + if test "$enable_perlinterp" = "dynamic"; then + if test "$perl_ok" = "yes" -a "X$libperl" != "X"; then + AC_DEFINE(DYNAMIC_PERL) + PERL_CFLAGS="-DDYNAMIC_PERL_DLL=\\\"$libperl\\\" $PERL_CFLAGS" + fi + fi + + if test "$fail_if_missing" = "yes" -a "$perl_ok" != "yes"; then + AC_MSG_ERROR([could not configure perl]) + fi +fi +AC_SUBST(shrpenv) +AC_SUBST(PERL_SRC) +AC_SUBST(PERL_OBJ) +AC_SUBST(PERL_PRO) +AC_SUBST(PERL_CFLAGS) +AC_SUBST(PERL_CFLAGS_EXTRA) +AC_SUBST(PERL_LIBS) + +AC_MSG_CHECKING(--enable-pythoninterp argument) +AC_ARG_ENABLE(pythoninterp, + [ --enable-pythoninterp[=OPTS] Include Python interpreter. [default=no] [OPTS=no/yes/dynamic]], , + [enable_pythoninterp="no"]) +AC_MSG_RESULT($enable_pythoninterp) +if test "$enable_pythoninterp" = "yes" -o "$enable_pythoninterp" = "dynamic"; then + if test "$has_eval" = "no"; then + AC_MSG_ERROR([cannot use Python with tiny features]) + fi + + dnl -- find the python executable + AC_MSG_CHECKING(--with-python-command argument) + AC_SUBST(vi_cv_path_python) + AC_ARG_WITH(python-command, [ --with-python-command=NAME name of the Python 2 command (default: python2 or python)], + vi_cv_path_python="$withval"; AC_MSG_RESULT($vi_cv_path_python), + AC_MSG_RESULT(no)) + + if test "X$vi_cv_path_python" = "X"; then + AC_PATH_PROGS(vi_cv_path_python, python2 python) + fi + if test "X$vi_cv_path_python" != "X"; then + + dnl -- get its version number + AC_CACHE_CHECK(Python version,vi_cv_var_python_version, + [[vi_cv_var_python_version=` + ${vi_cv_path_python} -c 'import sys; print sys.version[:3]'` + ]]) + + dnl -- it must be at least version 2.3 + AC_MSG_CHECKING(Python is 2.3 or better) + if ${vi_cv_path_python} -c \ + "import sys; sys.exit(${vi_cv_var_python_version} < 2.3)" + then + AC_MSG_RESULT(yep) + + dnl -- find where python thinks it was installed + AC_CACHE_CHECK(Python's install prefix,vi_cv_path_python_pfx, + [ vi_cv_path_python_pfx=` + ${vi_cv_path_python} -c \ + "import sys; print sys.prefix"` ]) + + dnl -- and where it thinks it runs + AC_CACHE_CHECK(Python's execution prefix,vi_cv_path_python_epfx, + [ vi_cv_path_python_epfx=` + ${vi_cv_path_python} -c \ + "import sys; print sys.exec_prefix"` ]) + + dnl -- python's internal library path + + AC_CACHE_VAL(vi_cv_path_pythonpath, + [ vi_cv_path_pythonpath=` + unset PYTHONPATH; + ${vi_cv_path_python} -c \ + "import sys, string; print string.join(sys.path,':')"` ]) + + dnl -- where the Python implementation library archives are + + AC_ARG_WITH(python-config-dir, + [ --with-python-config-dir=PATH Python's config directory (deprecated)], + [ vi_cv_path_python_conf="${withval}"; have_python_config_dir=1 ] ) + + AC_CACHE_CHECK(Python's configuration directory,vi_cv_path_python_conf, + [ + vi_cv_path_python_conf= + d=`${vi_cv_path_python} -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('LIBPL')"` + if test -d "$d" && test -f "$d/config.c"; then + vi_cv_path_python_conf="$d" + else + for path in "${vi_cv_path_python_pfx}" "${vi_cv_path_python_epfx}"; do + for subdir in lib64 lib share; do + d="${path}/${subdir}/python${vi_cv_var_python_version}/config" + if test -d "$d" && test -f "$d/config.c"; then + vi_cv_path_python_conf="$d" + fi + done + done + fi + ]) + + PYTHON_CONFDIR="${vi_cv_path_python_conf}" + + if test "X$PYTHON_CONFDIR" = "X"; then + AC_MSG_RESULT([can't find it!]) + else + + dnl -- we need to examine Python's config/Makefile too + dnl see what the interpreter is built from + AC_CACHE_VAL(vi_cv_path_python_plibs, + [ + pwd=`pwd` + tmp_mkf="$pwd/config-PyMake$$" + cat -- "${PYTHON_CONFDIR}/Makefile" - <<'eof' >"${tmp_mkf}" +__: + @echo "python_BASEMODLIBS='$(BASEMODLIBS)'" + @echo "python_LIBS='$(LIBS)'" + @echo "python_SYSLIBS='$(SYSLIBS)'" + @echo "python_LINKFORSHARED='$(LINKFORSHARED)'" + @echo "python_DLLLIBRARY='$(DLLLIBRARY)'" + @echo "python_INSTSONAME='$(INSTSONAME)'" + @echo "python_PYTHONFRAMEWORK='$(PYTHONFRAMEWORK)'" + @echo "python_PYTHONFRAMEWORKPREFIX='$(PYTHONFRAMEWORKPREFIX)'" + @echo "python_PYTHONFRAMEWORKINSTALLDIR='$(PYTHONFRAMEWORKINSTALLDIR)'" +eof + dnl -- delete the lines from make about Entering/Leaving directory + eval "`cd ${PYTHON_CONFDIR} && make -f "${tmp_mkf}" __ | sed '/ directory /d'`" + rm -f -- "${tmp_mkf}" + if test "x$MACOS_X" = "xyes" && test -n "${python_PYTHONFRAMEWORK}" && ${vi_cv_path_python} -c \ + "import sys; sys.exit(${vi_cv_var_python_version} < 2.3)"; then + vi_cv_path_python_plibs="-framework Python" + if test "x${vi_cv_path_python}" != "x/usr/bin/python" && test -n "${python_PYTHONFRAMEWORKPREFIX}"; then + vi_cv_path_python_plibs="-F${python_PYTHONFRAMEWORKPREFIX} -framework Python" + fi + else + vi_cv_path_python_plibs="-L${PYTHON_CONFDIR} -lpython${vi_cv_var_python_version}" + dnl -- Check if the path contained in python_LINKFORSHARED is + dnl usable for vim build. If not, make and try other + dnl candidates. + if test -n "${python_LINKFORSHARED}" && test -n "${python_PYTHONFRAMEWORKPREFIX}"; then + python_link_symbol=`echo ${python_LINKFORSHARED} | sed 's/\([[^ \t]][[^ \t]]*[[ \t]][[ \t]]*[[^ \t]][[^ \t]]*\)[[ \t]].*/\1/'` + python_link_path=`echo ${python_LINKFORSHARED} | sed 's/\([[^ \t]][[^ \t]]*[[ \t]][[ \t]]*[[^ \t]][[^ \t]]*\)[[ \t]][[ \t]]*\(.*\)/\2/'` + if test -n "${python_link_path}" && ! test -x "${python_link_path}"; then + dnl -- The path looks relative. Guess the absolute one using + dnl the prefix and try that. + python_link_path="${python_PYTHONFRAMEWORKPREFIX}/${python_link_path}" + if test -n "${python_link_path}" && ! test -x "${python_link_path}"; then + dnl -- A last resort. + python_link_path="${python_PYTHONFRAMEWORKINSTALLDIR}/Versions/${vi_cv_var_python_version}/${python_PYTHONFRAMEWORK}" + dnl -- No check is done. The last word is left to the + dnl "sanity" test on link flags that follows shortly. + fi + python_LINKFORSHARED="${python_link_symbol} ${python_link_path}" + fi + fi + vi_cv_path_python_plibs="${vi_cv_path_python_plibs} ${python_BASEMODLIBS} ${python_LIBS} ${python_SYSLIBS} ${python_LINKFORSHARED}" + dnl remove -ltermcap, it can conflict with an earlier -lncurses + vi_cv_path_python_plibs=`echo $vi_cv_path_python_plibs | sed s/-ltermcap//` + fi + ]) + AC_CACHE_CHECK(Python's dll name,vi_cv_dll_name_python, + [ + if test "X$python_DLLLIBRARY" != "X"; then + vi_cv_dll_name_python="$python_DLLLIBRARY" + else + vi_cv_dll_name_python="$python_INSTSONAME" + fi + ]) + + PYTHON_LIBS="${vi_cv_path_python_plibs}" + if test "${vi_cv_path_python_pfx}" = "${vi_cv_path_python_epfx}"; then + PYTHON_CFLAGS="-I${vi_cv_path_python_pfx}/include/python${vi_cv_var_python_version}" + else + PYTHON_CFLAGS="-I${vi_cv_path_python_pfx}/include/python${vi_cv_var_python_version} -I${vi_cv_path_python_epfx}/include/python${vi_cv_var_python_version}" + fi + if test "X$have_python_config_dir" = "X1" -a "$enable_pythoninterp" = "dynamic"; then + dnl Define PYTHON_HOME if --with-python-config-dir was used + PYTHON_CFLAGS="${PYTHON_CFLAGS} -DPYTHON_HOME='\"${vi_cv_path_python_pfx}\"'" + + fi + PYTHON_SRC="if_python.c" + PYTHON_OBJ="objects/if_python.o" + + dnl On FreeBSD linking with "-pthread" is required to use threads. + dnl _THREAD_SAFE must be used for compiling then. + dnl The "-pthread" is added to $LIBS, so that the following check for + dnl sigaltstack() will look in libc_r (it's there in libc!). + dnl Otherwise, when using GCC, try adding -pthread to $CFLAGS. GCC + dnl will then define target-specific defines, e.g., -D_REENTRANT. + dnl Don't do this for Mac OSX, -pthread will generate a warning. + AC_MSG_CHECKING([if -pthread should be used]) + threadsafe_flag= + thread_lib= + dnl if test "x$MACOS_X" != "xyes"; then + if test "$vim_cv_uname_output" != Darwin; then + test "$GCC" = yes && threadsafe_flag="-pthread" + if test "$vim_cv_uname_output" = FreeBSD; then + threadsafe_flag="-D_THREAD_SAFE" + thread_lib="-pthread" + fi + if test "$vim_cv_uname_output" = SunOS; then + threadsafe_flag="-pthreads" + fi + fi + libs_save_old=$LIBS + if test -n "$threadsafe_flag"; then + cflags_save=$CFLAGS + CFLAGS="$CFLAGS $threadsafe_flag" + LIBS="$LIBS $thread_lib" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ ])], + AC_MSG_RESULT(yes); PYTHON_CFLAGS="$PYTHON_CFLAGS $threadsafe_flag", + AC_MSG_RESULT(no); LIBS=$libs_save_old + ) + CFLAGS=$cflags_save + else + AC_MSG_RESULT(no) + fi + + dnl Check that compiling a simple program still works with the flags + dnl added for Python. + AC_MSG_CHECKING([if compile and link flags for Python are sane]) + cflags_save=$CFLAGS + libs_save=$LIBS + CFLAGS="$CFLAGS $PYTHON_CFLAGS" + LIBS="$LIBS $PYTHON_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ ])], + AC_MSG_RESULT(yes); python_ok=yes, + AC_MSG_RESULT(no: PYTHON DISABLED); python_ok=no) + CFLAGS=$cflags_save + LIBS=$libs_save + if test $python_ok = yes; then + AC_DEFINE(FEAT_PYTHON) + else + LIBS=$libs_save_old + PYTHON_SRC= + PYTHON_OBJ= + PYTHON_LIBS= + PYTHON_CFLAGS= + fi + fi + else + AC_MSG_RESULT(too old) + fi + fi + + if test "$fail_if_missing" = "yes" -a "$python_ok" != "yes"; then + AC_MSG_ERROR([could not configure python]) + fi +fi + +AC_SUBST(PYTHON_LIBS) +AC_SUBST(PYTHON_CFLAGS) +AC_SUBST(PYTHON_CFLAGS_EXTRA) +AC_SUBST(PYTHON_SRC) +AC_SUBST(PYTHON_OBJ) + + +AC_MSG_CHECKING(--enable-python3interp argument) +AC_ARG_ENABLE(python3interp, + [ --enable-python3interp[=OPTS] Include Python3 interpreter. [default=no] [OPTS=no/yes/dynamic]], , + [enable_python3interp="no"]) +AC_MSG_RESULT($enable_python3interp) +if test "$enable_python3interp" = "yes" -o "$enable_python3interp" = "dynamic"; then + if test "$has_eval" = "no"; then + AC_MSG_ERROR([cannot use Python with tiny features]) + fi + + dnl -- find the python3 executable + AC_MSG_CHECKING(--with-python3-command argument) + AC_SUBST(vi_cv_path_python3) + AC_ARG_WITH(python3-command, [ --with-python3-command=NAME name of the Python 3 command (default: python3 or python)], + vi_cv_path_python3="$withval"; AC_MSG_RESULT($vi_cv_path_python3), + AC_MSG_RESULT(no)) + + if test "X$vi_cv_path_python3" = "X"; then + AC_PATH_PROGS(vi_cv_path_python3, python3 python) + fi + if test "X$vi_cv_path_python3" != "X"; then + + dnl -- get its version number + AC_CACHE_CHECK(Python version,vi_cv_var_python3_version, + [[vi_cv_var_python3_version=` + ${vi_cv_path_python3} -c 'import sys; print("{}.{}".format(sys.version_info.major, sys.version_info.minor))'` + ]]) + + dnl -- it must be at least version 3 + AC_MSG_CHECKING(Python is 3.0 or better) + if ${vi_cv_path_python3} -c \ + "import sys; sys.exit(${vi_cv_var_python3_version} < 3.0)" + then + AC_MSG_RESULT(yep) + + dnl -- get abiflags for python 3.2 or higher (PEP 3149) + AC_CACHE_CHECK(Python's abiflags,vi_cv_var_python3_abiflags, + [ + vi_cv_var_python3_abiflags= + if ${vi_cv_path_python3} -c \ + "import sys; sys.exit(${vi_cv_var_python3_version} < 3.2)" + then + vi_cv_var_python3_abiflags=`${vi_cv_path_python3} -c \ + "import sys; print(sys.abiflags)"` + fi ]) + + dnl -- find where python3 thinks it was installed + AC_CACHE_CHECK(Python's install prefix,vi_cv_path_python3_pfx, + [ vi_cv_path_python3_pfx=` + ${vi_cv_path_python3} -c \ + "import sys; print(sys.prefix)"` ]) + + dnl -- and where it thinks it runs + AC_CACHE_CHECK(Python's execution prefix,vi_cv_path_python3_epfx, + [ vi_cv_path_python3_epfx=` + ${vi_cv_path_python3} -c \ + "import sys; print(sys.exec_prefix)"` ]) + + dnl -- python3's internal library path + + AC_CACHE_VAL(vi_cv_path_python3path, + [ vi_cv_path_python3path=` + unset PYTHONPATH; + ${vi_cv_path_python3} -c \ + "import sys, string; print(':'.join(sys.path))"` ]) + + dnl -- where the Python implementation library archives are + + AC_ARG_WITH(python3-config-dir, + [ --with-python3-config-dir=PATH Python's config directory (deprecated)], + [ vi_cv_path_python3_conf="${withval}"; have_python3_config_dir=1 ] ) + + AC_CACHE_CHECK(Python's configuration directory,vi_cv_path_python3_conf, + [ + vi_cv_path_python3_conf= + config_dir="config-${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}" + d=`${vi_cv_path_python3} -c "import sysconfig; print(sysconfig.get_config_var('LIBPL'))" 2> /dev/null` + if test "x$d" = "x"; then + d=`${vi_cv_path_python3} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBPL'))"` + fi + if test -d "$d" && test -f "$d/config.c"; then + vi_cv_path_python3_conf="$d" + else + for path in "${vi_cv_path_python3_pfx}" "${vi_cv_path_python3_epfx}"; do + for subdir in lib64 lib share; do + d="${path}/${subdir}/python${vi_cv_var_python3_version}/${config_dir}" + if test -d "$d" && test -f "$d/config.c"; then + vi_cv_path_python3_conf="$d" + fi + done + done + fi + ]) + + PYTHON3_CONFDIR="${vi_cv_path_python3_conf}" + + if test "X$PYTHON3_CONFDIR" = "X"; then + AC_MSG_RESULT([can't find it!]) + else + + dnl -- we need to examine Python's config/Makefile too + dnl see what the interpreter is built from + AC_CACHE_VAL(vi_cv_path_python3_plibs, + [ + pwd=`pwd` + tmp_mkf="$pwd/config-PyMake$$" + cat -- "${PYTHON3_CONFDIR}/Makefile" - <<'eof' >"${tmp_mkf}" +__: + @echo "python3_BASEMODLIBS='$(BASEMODLIBS)'" + @echo "python3_LIBS='$(LIBS)'" + @echo "python3_SYSLIBS='$(SYSLIBS)'" + @echo "python3_DLLLIBRARY='$(DLLLIBRARY)'" + @echo "python3_INSTSONAME='$(INSTSONAME)'" +eof + dnl -- delete the lines from make about Entering/Leaving directory + eval "`cd ${PYTHON3_CONFDIR} && make -f "${tmp_mkf}" __ | sed '/ directory /d'`" + rm -f -- "${tmp_mkf}" + vi_cv_path_python3_plibs="-L${PYTHON3_CONFDIR} -lpython${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}" + vi_cv_path_python3_plibs="${vi_cv_path_python3_plibs} ${python3_BASEMODLIBS} ${python3_LIBS} ${python3_SYSLIBS}" + dnl remove -ltermcap, it can conflict with an earlier -lncurses + vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-ltermcap//` + vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-lffi//` + ]) + AC_CACHE_CHECK(Python3's dll name,vi_cv_dll_name_python3, + [ + if test "X$python3_DLLLIBRARY" != "X"; then + vi_cv_dll_name_python3="$python3_DLLLIBRARY" + else + vi_cv_dll_name_python3="$python3_INSTSONAME" + fi + ]) + + PYTHON3_LIBS="${vi_cv_path_python3_plibs}" + if test "${vi_cv_path_python3_pfx}" = "${vi_cv_path_python3_epfx}"; then + PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}" + else + PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags} -I${vi_cv_path_python3_epfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}" + fi + if test "X$have_python3_config_dir" = "X1" -a "$enable_python3interp" = "dynamic"; then + dnl Define PYTHON3_HOME if --with-python-config-dir was used + PYTHON3_CFLAGS="${PYTHON3_CFLAGS} -DPYTHON3_HOME='L\"${vi_cv_path_python3_pfx}\"'" + fi + PYTHON3_SRC="if_python3.c" + PYTHON3_OBJ="objects/if_python3.o" + + dnl On FreeBSD linking with "-pthread" is required to use threads. + dnl _THREAD_SAFE must be used for compiling then. + dnl The "-pthread" is added to $LIBS, so that the following check for + dnl sigaltstack() will look in libc_r (it's there in libc!). + dnl Otherwise, when using GCC, try adding -pthread to $CFLAGS. GCC + dnl will then define target-specific defines, e.g., -D_REENTRANT. + dnl Don't do this for Mac OSX, -pthread will generate a warning. + AC_MSG_CHECKING([if -pthread should be used]) + threadsafe_flag= + thread_lib= + dnl if test "x$MACOS_X" != "xyes"; then + if test "$vim_cv_uname_output" != Darwin; then + test "$GCC" = yes && threadsafe_flag="-pthread" + if test "$vim_cv_uname_output" = FreeBSD; then + threadsafe_flag="-D_THREAD_SAFE" + thread_lib="-pthread" + fi + if test "$vim_cv_uname_output" = SunOS; then + threadsafe_flag="-pthreads" + fi + fi + libs_save_old=$LIBS + if test -n "$threadsafe_flag"; then + cflags_save=$CFLAGS + CFLAGS="$CFLAGS $threadsafe_flag" + LIBS="$LIBS $thread_lib" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ ])], + AC_MSG_RESULT(yes); PYTHON3_CFLAGS="$PYTHON3_CFLAGS $threadsafe_flag", + AC_MSG_RESULT(no); LIBS=$libs_save_old + ) + CFLAGS=$cflags_save + else + AC_MSG_RESULT(no) + fi + + dnl check that compiling a simple program still works with the flags + dnl added for Python. + AC_MSG_CHECKING([if compile and link flags for Python 3 are sane]) + cflags_save=$CFLAGS + libs_save=$LIBS + CFLAGS="$CFLAGS $PYTHON3_CFLAGS" + LIBS="$LIBS $PYTHON3_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ ])], + AC_MSG_RESULT(yes); python3_ok=yes, + AC_MSG_RESULT(no: PYTHON3 DISABLED); python3_ok=no) + CFLAGS=$cflags_save + LIBS=$libs_save + if test "$python3_ok" = yes; then + AC_DEFINE(FEAT_PYTHON3) + else + LIBS=$libs_save_old + PYTHON3_SRC= + PYTHON3_OBJ= + PYTHON3_LIBS= + PYTHON3_CFLAGS= + fi + fi + else + AC_MSG_RESULT(too old) + fi + fi + if test "$fail_if_missing" = "yes" -a "$python3_ok" != "yes"; then + AC_MSG_ERROR([could not configure python3]) + fi +fi + +AC_SUBST(PYTHON3_LIBS) +AC_SUBST(PYTHON3_CFLAGS) +AC_SUBST(PYTHON3_CFLAGS_EXTRA) +AC_SUBST(PYTHON3_SRC) +AC_SUBST(PYTHON3_OBJ) + +dnl if python2.x and python3.x are enabled one can only link in code +dnl with dlopen(), dlsym(), dlclose() +if test "$python_ok" = yes && test "$python3_ok" = yes; then + AC_DEFINE(DYNAMIC_PYTHON) + AC_DEFINE(DYNAMIC_PYTHON3) + AC_MSG_CHECKING(whether we can do without RTLD_GLOBAL for Python) + cflags_save=$CFLAGS + CFLAGS="$CFLAGS $PYTHON_CFLAGS" + libs_save=$LIBS + dnl -ldl must go first to make this work on Archlinux (Roland Puntaier) + LIBS="-ldl $LIBS" + AC_RUN_IFELSE([AC_LANG_SOURCE([ + #include + /* If this program fails, then RTLD_GLOBAL is needed. + * RTLD_GLOBAL will be used and then it is not possible to + * have both python versions enabled in the same vim instance. + * Only the first python version used will be switched on. + */ + + static int no_rtl_global_needed_for(char *python_instsoname, char *prefix) + { + int needed = 0; + void* pylib = dlopen(python_instsoname, RTLD_LAZY|RTLD_LOCAL); + if (pylib != 0) + { + void (*pfx)(char *home) = dlsym(pylib, "Py_SetPythonHome"); + void (*init)(void) = dlsym(pylib, "Py_Initialize"); + int (*simple)(char*) = dlsym(pylib, "PyRun_SimpleString"); + void (*final)(void) = dlsym(pylib, "Py_Finalize"); + (*pfx)(prefix); + (*init)(); + needed = (*simple)("import termios") == -1; + (*final)(); + dlclose(pylib); + } + return !needed; + } + + int main() + { + int not_needed = 0; + if (no_rtl_global_needed_for("${vi_cv_dll_name_python}", "${vi_cv_path_python_pfx}")) + not_needed = 1; + return !not_needed; + }])], + [AC_MSG_RESULT(yes);AC_DEFINE(PY_NO_RTLD_GLOBAL)], [AC_MSG_RESULT(no)]) + + CFLAGS=$cflags_save + LIBS=$libs_save + + AC_MSG_CHECKING(whether we can do without RTLD_GLOBAL for Python3) + cflags_save=$CFLAGS + CFLAGS="$CFLAGS $PYTHON3_CFLAGS" + libs_save=$LIBS + dnl -ldl must go first to make this work on Archlinux (Roland Puntaier) + LIBS="-ldl $LIBS" + AC_RUN_IFELSE([AC_LANG_SOURCE([ + #include + #include + /* If this program fails, then RTLD_GLOBAL is needed. + * RTLD_GLOBAL will be used and then it is not possible to + * have both python versions enabled in the same vim instance. + * Only the first python version used will be switched on. + */ + + static int no_rtl_global_needed_for(char *python_instsoname, wchar_t *prefix) + { + int needed = 0; + void* pylib = dlopen(python_instsoname, RTLD_LAZY|RTLD_LOCAL); + if (pylib != 0) + { + void (*pfx)(wchar_t *home) = dlsym(pylib, "Py_SetPythonHome"); + void (*init)(void) = dlsym(pylib, "Py_Initialize"); + int (*simple)(char*) = dlsym(pylib, "PyRun_SimpleString"); + void (*final)(void) = dlsym(pylib, "Py_Finalize"); + (*pfx)(prefix); + (*init)(); + needed = (*simple)("import termios") == -1; + (*final)(); + dlclose(pylib); + } + return !needed; + } + + int main() + { + int not_needed = 0; + if (no_rtl_global_needed_for("${vi_cv_dll_name_python3}", L"${vi_cv_path_python3_pfx}")) + not_needed = 1; + return !not_needed; + }])], + [AC_MSG_RESULT(yes);AC_DEFINE(PY3_NO_RTLD_GLOBAL)], [AC_MSG_RESULT(no)]) + + CFLAGS=$cflags_save + LIBS=$libs_save + + PYTHON_SRC="if_python.c" + PYTHON_OBJ="objects/if_python.o" + PYTHON_CFLAGS="$PYTHON_CFLAGS -DDYNAMIC_PYTHON_DLL=\\\"${vi_cv_dll_name_python}\\\"" + PYTHON_LIBS= + PYTHON3_SRC="if_python3.c" + PYTHON3_OBJ="objects/if_python3.o" + PYTHON3_CFLAGS="$PYTHON3_CFLAGS -DDYNAMIC_PYTHON3_DLL=\\\"${vi_cv_dll_name_python3}\\\"" + PYTHON3_LIBS= +elif test "$python_ok" = yes && test "$enable_pythoninterp" = "dynamic"; then + AC_DEFINE(DYNAMIC_PYTHON) + PYTHON_SRC="if_python.c" + PYTHON_OBJ="objects/if_python.o" + PYTHON_CFLAGS="$PYTHON_CFLAGS -DDYNAMIC_PYTHON_DLL=\\\"${vi_cv_dll_name_python}\\\"" + PYTHON_LIBS= +elif test "$python_ok" = yes; then + dnl Check that adding -fPIE works. It may be needed when using a static + dnl Python library. + AC_MSG_CHECKING([if -fPIE can be added for Python]) + cflags_save=$CFLAGS + libs_save=$LIBS + CFLAGS="$CFLAGS $PYTHON_CFLAGS -fPIE" + LIBS="$LIBS $PYTHON_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ ])], + AC_MSG_RESULT(yes); fpie_ok=yes, + AC_MSG_RESULT(no); fpie_ok=no) + CFLAGS=$cflags_save + LIBS=$libs_save + if test $fpie_ok = yes; then + PYTHON_CFLAGS="$PYTHON_CFLAGS -fPIE" + fi +elif test "$python3_ok" = yes && test "$enable_python3interp" = "dynamic"; then + AC_DEFINE(DYNAMIC_PYTHON3) + PYTHON3_SRC="if_python3.c" + PYTHON3_OBJ="objects/if_python3.o" + PYTHON3_CFLAGS="$PYTHON3_CFLAGS -DDYNAMIC_PYTHON3_DLL=\\\"${vi_cv_dll_name_python3}\\\"" + PYTHON3_LIBS= +elif test "$python3_ok" = yes; then + dnl Check that adding -fPIE works. It may be needed when using a static + dnl Python library. + AC_MSG_CHECKING([if -fPIE can be added for Python3]) + cflags_save=$CFLAGS + libs_save=$LIBS + CFLAGS="$CFLAGS $PYTHON3_CFLAGS -fPIE" + LIBS="$LIBS $PYTHON3_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ ])], + AC_MSG_RESULT(yes); fpie_ok=yes, + AC_MSG_RESULT(no); fpie_ok=no) + CFLAGS=$cflags_save + LIBS=$libs_save + if test $fpie_ok = yes; then + PYTHON3_CFLAGS="$PYTHON3_CFLAGS -fPIE" + fi +fi + +AC_MSG_CHECKING(--enable-tclinterp argument) +AC_ARG_ENABLE(tclinterp, + [ --enable-tclinterp[=OPTS] Include Tcl interpreter. [default=no] [OPTS=no/yes/dynamic]], , + [enable_tclinterp="no"]) +AC_MSG_RESULT($enable_tclinterp) + +if test "$enable_tclinterp" = "yes" -o "$enable_tclinterp" = "dynamic"; then + + dnl on FreeBSD tclsh is a silly script, look for tclsh8.[5420] + AC_MSG_CHECKING(--with-tclsh argument) + AC_ARG_WITH(tclsh, [ --with-tclsh=PATH which tclsh to use (default: tclsh8.0)], + tclsh_name="$withval"; AC_MSG_RESULT($tclsh_name), + tclsh_name="tclsh8.5"; AC_MSG_RESULT(no)) + AC_PATH_PROG(vi_cv_path_tcl, $tclsh_name) + AC_SUBST(vi_cv_path_tcl) + + dnl when no specific version specified, also try 8.4, 8.2 and 8.0 + if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.5"; then + tclsh_name="tclsh8.4" + AC_PATH_PROG(vi_cv_path_tcl, $tclsh_name) + fi + if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.4"; then + tclsh_name="tclsh8.2" + AC_PATH_PROG(vi_cv_path_tcl, $tclsh_name) + fi + if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.2"; then + tclsh_name="tclsh8.0" + AC_PATH_PROG(vi_cv_path_tcl, $tclsh_name) + fi + dnl still didn't find it, try without version number + if test "X$vi_cv_path_tcl" = "X"; then + tclsh_name="tclsh" + AC_PATH_PROG(vi_cv_path_tcl, $tclsh_name) + fi + if test "X$vi_cv_path_tcl" != "X"; then + AC_MSG_CHECKING(Tcl version) + if echo 'exit [[expr [info tclversion] < 8.0]]' | "$vi_cv_path_tcl" - ; then + tclver=`echo 'puts [[info tclversion]]' | $vi_cv_path_tcl -` + AC_MSG_RESULT($tclver - OK); + tclloc=`echo 'set l [[info library]];set i [[string last lib $l]];incr i -2;puts [[string range $l 0 $i]]' | $vi_cv_path_tcl -` + tcldll=`echo 'puts libtcl[[info tclversion]][[info sharedlibextension]]' | $vi_cv_path_tcl -` + + AC_MSG_CHECKING(for location of Tcl include) + if test "x$MACOS_X" != "xyes"; then + tclinc="$tclloc/include $tclloc/include/tcl $tclloc/include/tcl$tclver /usr/local/include /usr/local/include/tcl$tclver /usr/include /usr/include/tcl$tclver" + else + dnl For all macOS, use the value from TCL in case use of, say, homebrew + dnl For Mac OS X 10.3, use the OS-provided framework location + dnl For Mac OS X 10.14, the OS-provided framework location doesn't contain the headers, so also check the Xcode SDK + tclinc="$tclloc/include $tclloc/include/tcl $tclloc/include/tcl$tclver /System/Library/Frameworks/Tcl.framework/Headers `xcrun --show-sdk-path`/System/Library/Frameworks/Tcl.framework/Versions/Current/Headers" + fi + TCL_INC= + for try in $tclinc; do + if test -f "$try/tcl.h"; then + AC_MSG_RESULT($try/tcl.h) + TCL_INC=$try + break + fi + done + if test -z "$TCL_INC"; then + AC_MSG_RESULT() + SKIP_TCL=YES + fi + if test -z "$SKIP_TCL"; then + AC_MSG_CHECKING(for location of tclConfig.sh script) + if test "x$MACOS_X" != "xyes"; then + tclcnf=`echo $tclinc | sed s/include/lib/g` + tclcnf="$tclcnf `echo $tclinc | sed s/include/lib64/g`" + else + dnl For all macOS, use the value from TCL in case use of, say, homebrew + dnl For Mac OS X 10.3, use the OS-provided framework location + dnl For Mac OS X 10.14, the OS-provided framework location doesn't contain the headers, so also check the Xcode SDK + tclcnf=`echo $tclinc | sed s/include/lib/g` + tclcnf="$tclcnf /System/Library/Frameworks/Tcl.framework `xcrun --show-sdk-path`/System/Library/Frameworks/Tcl.framework" + fi + for try in $tclcnf; do + if test -f "$try/tclConfig.sh"; then + AC_MSG_RESULT($try/tclConfig.sh) + . "$try/tclConfig.sh" + dnl use eval, because tcl 8.2 includes ${TCL_DBGX} + if test "$enable_tclinterp" = "dynamic"; then + TCL_LIBS=`eval echo "$TCL_STUB_LIB_SPEC $TCL_LIBS"` + else + TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"` + fi + dnl Use $TCL_DEFS for -D_THREAD_SAFE et al. But only use the + dnl "-D_ABC" items. Watch out for -DFOO=long\ long. + TCL_DEFS=`echo $TCL_DEFS | sed -e 's/\\\\ /\\\\X/g' | tr ' ' '\012' | sed -e '/^[[^-]]/d' -e '/^-[[^D]]/d' -e '/-D[[^_]]/d' -e 's/-D_/ -D_/' | tr '\012' ' ' | sed -e 's/\\\\X/\\\\ /g'` + break + fi + done + if test -z "$TCL_LIBS"; then + AC_MSG_RESULT() + AC_MSG_CHECKING(for Tcl library by myself) + tcllib=`echo $tclinc | sed s/include/lib/g` + tcllib="$tcllib `echo $tclinc | sed s/include/lib64/g`" + for ext in .so .a ; do + for ver in "" $tclver ; do + for try in $tcllib ; do + trylib=tcl$ver$ext + if test -f "$try/lib$trylib" ; then + AC_MSG_RESULT($try/lib$trylib) + TCL_LIBS="-L\"$try\" -ltcl$ver -ldl -lm" + if test "$vim_cv_uname_output" = SunOS && + echo $vim_cv_uname_r_output | grep '^5' >/dev/null; then + TCL_LIBS="$TCL_LIBS -R $try" + fi + break 3 + fi + done + done + done + if test -z "$TCL_LIBS"; then + AC_MSG_RESULT() + SKIP_TCL=YES + fi + fi + if test -z "$SKIP_TCL"; then + AC_DEFINE(FEAT_TCL) + TCL_SRC=if_tcl.c + TCL_OBJ=objects/if_tcl.o + TCL_PRO=if_tcl.pro + TCL_CFLAGS="-I$TCL_INC $TCL_DEFS" + fi + fi + else + AC_MSG_RESULT(too old; need Tcl version 8.0 or later) + fi + fi + if test "$enable_tclinterp" = "dynamic"; then + if test "X$TCL_SRC" != "X" -a "X$tcldll" != "X"; then + AC_DEFINE(DYNAMIC_TCL) + TCL_CFLAGS="-DDYNAMIC_TCL_DLL=\\\"$tcldll\\\" -DDYNAMIC_TCL_VER=\\\"$tclver\\\" $TCL_CFLAGS" + fi + fi + if test "$fail_if_missing" = "yes" -a -z "$TCL_SRC"; then + AC_MSG_ERROR([could not configure Tcl]) + fi +fi +AC_SUBST(TCL_SRC) +AC_SUBST(TCL_OBJ) +AC_SUBST(TCL_PRO) +AC_SUBST(TCL_CFLAGS) +AC_SUBST(TCL_CFLAGS_EXTRA) +AC_SUBST(TCL_LIBS) + +AC_MSG_CHECKING(--enable-rubyinterp argument) +AC_ARG_ENABLE(rubyinterp, + [ --enable-rubyinterp[=OPTS] Include Ruby interpreter. [default=no] [OPTS=no/yes/dynamic]], , + [enable_rubyinterp="no"]) +AC_MSG_RESULT($enable_rubyinterp) +if test "$enable_rubyinterp" = "yes" -o "$enable_rubyinterp" = "dynamic"; then + if test "$has_eval" = "no"; then + AC_MSG_ERROR([cannot use Ruby with tiny features]) + fi + + AC_MSG_CHECKING(--with-ruby-command argument) + AC_SUBST(vi_cv_path_ruby) + AC_ARG_WITH(ruby-command, [ --with-ruby-command=RUBY name of the Ruby command (default: ruby)], + RUBY_CMD="$withval"; vi_cv_path_ruby="$withval"; AC_MSG_RESULT($RUBY_CMD), + RUBY_CMD="ruby"; AC_MSG_RESULT(defaulting to $RUBY_CMD)) + AC_PATH_PROG(vi_cv_path_ruby, $RUBY_CMD) + if test "X$vi_cv_path_ruby" != "X"; then + AC_MSG_CHECKING(Ruby version) + if $vi_cv_path_ruby -e 'RUBY_VERSION >= "1.9.1" or exit 1' >/dev/null 2>/dev/null; then + AC_MSG_RESULT(OK) + AC_MSG_CHECKING(Ruby rbconfig) + ruby_rbconfig="RbConfig" + if ! $vi_cv_path_ruby -r rbconfig -e 'RbConfig' >/dev/null 2>/dev/null; then + ruby_rbconfig="Config" + fi + AC_MSG_RESULT($ruby_rbconfig) + AC_MSG_CHECKING(Ruby header files) + rubyhdrdir=`$vi_cv_path_ruby -r mkmf -e "print $ruby_rbconfig::CONFIG[['rubyhdrdir']] || $ruby_rbconfig::CONFIG[['archdir']] || \\$hdrdir" 2>/dev/null` + if test "X$rubyhdrdir" != "X"; then + AC_MSG_RESULT($rubyhdrdir) + RUBY_CFLAGS="-I$rubyhdrdir" + rubyarchdir=`$vi_cv_path_ruby -r rbconfig -e "print ($ruby_rbconfig::CONFIG.has_key? 'rubyarchhdrdir') ? $ruby_rbconfig::CONFIG[['rubyarchhdrdir']] : '$rubyhdrdir/'+$ruby_rbconfig::CONFIG[['arch']]"` + if test -d "$rubyarchdir"; then + RUBY_CFLAGS="$RUBY_CFLAGS -I$rubyarchdir" + fi + rubyversion=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig::CONFIG[['ruby_version']].gsub(/\./, '')[[0,2]]"` + if test "X$rubyversion" = "X"; then + rubyversion=`$vi_cv_path_ruby -e "print RUBY_VERSION.gsub(/\./, '')[[0,2]]"` + fi + RUBY_CFLAGS="$RUBY_CFLAGS -DRUBY_VERSION=$rubyversion" + rubylibs=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig::CONFIG[['LIBS']]"` + if test "X$rubylibs" != "X"; then + RUBY_LIBS="$rubylibs" + fi + librubyarg=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG[['LIBRUBYARG']])"` + librubya=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG[['LIBRUBY_A']])"` + rubylibdir=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG[['libdir']])"` + if test -f "$rubylibdir/$librubya" || expr "$librubyarg" : "-lruby"; then + RUBY_LIBS="$RUBY_LIBS -L$rubylibdir" + elif test "$librubyarg" = "libruby.a"; then + dnl required on Mac OS 10.3 where libruby.a doesn't exist + librubyarg="-lruby" + RUBY_LIBS="$RUBY_LIBS -L$rubylibdir" + fi + + if test "X$librubyarg" != "X"; then + RUBY_LIBS="$librubyarg $RUBY_LIBS" + fi + + dnl Here the Ruby LDFLAGS used to be added to LDFLAGS, but that turns + dnl out to cause trouble and was removed. + + RUBY_SRC="if_ruby.c" + RUBY_OBJ="objects/if_ruby.o" + RUBY_PRO="if_ruby.pro" + AC_DEFINE(FEAT_RUBY) + if test "$enable_rubyinterp" = "dynamic"; then + libruby_soname=`$vi_cv_path_ruby -r rbconfig -e "puts $ruby_rbconfig::CONFIG[['LIBRUBY_ALIASES']].split[[0]]"` + if test -z "$libruby_soname"; then + libruby_soname=`$vi_cv_path_ruby -r rbconfig -e "puts $ruby_rbconfig::CONFIG[['LIBRUBY_SO']]"` + fi + AC_DEFINE(DYNAMIC_RUBY) + RUBY_CFLAGS="-DDYNAMIC_RUBY_DLL=\\\"$libruby_soname\\\" $RUBY_CFLAGS" + RUBY_LIBS= + fi + if test "X$CLANG_VERSION" != "X" -a "$rubyversion" -ge 30; then + RUBY_CFLAGS="$RUBY_CFLAGS -fdeclspec" + fi + else + AC_MSG_RESULT(not found; disabling Ruby) + fi + else + AC_MSG_RESULT(too old; need Ruby version 1.9.1 or later) + fi + fi + + if test "$fail_if_missing" = "yes" -a -z "$RUBY_OBJ"; then + AC_MSG_ERROR([could not configure Ruby]) + fi +fi +AC_SUBST(RUBY_SRC) +AC_SUBST(RUBY_OBJ) +AC_SUBST(RUBY_PRO) +AC_SUBST(RUBY_CFLAGS) +AC_SUBST(RUBY_CFLAGS_EXTRA) +AC_SUBST(RUBY_LIBS) + +AC_MSG_CHECKING(--enable-cscope argument) +AC_ARG_ENABLE(cscope, + [ --enable-cscope Include cscope interface.], , + [enable_cscope="no"]) +AC_MSG_RESULT($enable_cscope) +if test "$enable_cscope" = "yes"; then + AC_DEFINE(FEAT_CSCOPE) +fi + +AC_MSG_CHECKING(--disable-netbeans argument) +AC_ARG_ENABLE(netbeans, + [ --disable-netbeans Disable NetBeans integration support.], + , [enable_netbeans="yes"]) +if test "$enable_netbeans" = "yes"; then + if test "$has_eval" = "no"; then + AC_MSG_RESULT([cannot use NetBeans with tiny features]) + enable_netbeans="no" + else + AC_MSG_RESULT(no) + fi +else + AC_MSG_RESULT(yes) +fi + +AC_MSG_CHECKING(--disable-channel argument) +AC_ARG_ENABLE(channel, + [ --disable-channel Disable process communication support.], + , [enable_channel="yes"]) +if test "$enable_channel" = "yes"; then + if test "$has_eval" = "no"; then + AC_MSG_RESULT([cannot use channels with tiny features]) + enable_channel="no" + else + AC_MSG_RESULT(no) + fi +else + if test "$enable_netbeans" = "yes"; then + AC_MSG_RESULT([yes, netbeans also disabled]) + enable_netbeans="no" + else + AC_MSG_RESULT(yes) + fi +fi + +if test "$enable_channel" = "yes"; then + dnl On Solaris we need the socket library, or on Haiku the network library. + if test "x$HAIKU" = "xyes"; then + AC_CHECK_LIB(network, socket) + else + AC_CHECK_LIB(socket, socket) + fi + + AC_CACHE_CHECK([whether compiling with IPv6 networking is possible], [vim_cv_ipv6_networking], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#include +#include +#include +#include +#include +#include +#include +#include +#include + /* Check bitfields */ + struct nbbuf { + unsigned int initDone:1; + unsigned short signmaplen; + }; + ], [ + /* Check creating a socket. */ + struct sockaddr_in server; + struct addrinfo *res; + (void)socket(AF_INET, SOCK_STREAM, 0); + (void)htons(100); + (void)getaddrinfo("microsoft.com", NULL, NULL, &res); + if (errno == ECONNREFUSED) + (void)connect(1, (struct sockaddr *)&server, sizeof(server)); + (void)freeaddrinfo(res); + ])], + [vim_cv_ipv6_networking="yes"], + [vim_cv_ipv6_networking="no"])]) + + if test "x$vim_cv_ipv6_networking" = "xyes"; then + AC_DEFINE(FEAT_IPV6) + AC_CHECK_FUNCS(inet_ntop) + else + dnl On Solaris we need the nsl library. + AC_CHECK_LIB(nsl, gethostbyname) + AC_CACHE_CHECK([whether compiling with IPv4 networking is possible], [vim_cv_ipv4_networking], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#include +#include +#include +#include +#include +#include +#include +#include +#include + /* Check bitfields */ + struct nbbuf { + unsigned int initDone:1; + unsigned short signmaplen; + }; + ], [ + /* Check creating a socket. */ + struct sockaddr_in server; + (void)socket(AF_INET, SOCK_STREAM, 0); + (void)htons(100); + (void)gethostbyname("microsoft.com"); + if (errno == ECONNREFUSED) + (void)connect(1, (struct sockaddr *)&server, sizeof(server)); + ])], + [vim_cv_ipv4_networking="yes"], + [vim_cv_ipv4_networking="no"; enable_netbeans="no"; enable_channel="no"])]) + fi +fi +if test "$enable_netbeans" = "yes"; then + AC_DEFINE(FEAT_NETBEANS_INTG) + NETBEANS_SRC="netbeans.c" + AC_SUBST(NETBEANS_SRC) + NETBEANS_OBJ="objects/netbeans.o" + AC_SUBST(NETBEANS_OBJ) +fi +if test "$enable_channel" = "yes"; then + AC_DEFINE(FEAT_JOB_CHANNEL) + CHANNEL_SRC="job.c channel.c" + AC_SUBST(CHANNEL_SRC) + CHANNEL_OBJ="objects/job.o objects/channel.o" + AC_SUBST(CHANNEL_OBJ) +fi + +AC_MSG_CHECKING(--enable-terminal argument) +AC_ARG_ENABLE(terminal, + [ --enable-terminal Enable terminal emulation support.], + , [enable_terminal="auto"]) +if test "$enable_terminal" = "yes" || test "$enable_terminal" = "auto" -a "x$features" = "xhuge" ; then + if test "$has_eval" = "no"; then + AC_MSG_RESULT([cannot use terminal emulator with tiny features]) + enable_terminal="no" + else + if test "$enable_terminal" = "auto"; then + enable_terminal="yes" + AC_MSG_RESULT(defaulting to yes) + else + AC_MSG_RESULT(yes) + fi + fi +else + if test "$enable_terminal" = "auto"; then + enable_terminal="no" + AC_MSG_RESULT(defaulting to no) + else + AC_MSG_RESULT(no) + fi +fi +if test "$enable_terminal" = "yes" -a "$enable_channel" = "yes"; then + AC_DEFINE(FEAT_TERMINAL) + TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/creen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c" + AC_SUBST(TERM_SRC) + TERM_OBJ="objects/vterm_encoding.o objects/vterm_keyboard.o objects/vterm_mouse.o objects/vterm_parser.o objects/vterm_pen.o objects/vterm_screen.o objects/vterm_state.o objects/vterm_unicode.o objects/vterm_vterm.o" + AC_SUBST(TERM_OBJ) + TERM_TEST="test_libvterm" + AC_SUBST(TERM_TEST) +fi + +AC_MSG_CHECKING(--enable-autoservername argument) +AC_ARG_ENABLE(autoservername, + [ --enable-autoservername Automatically define servername at vim startup.], , + [enable_autoservername="no"]) +AC_MSG_RESULT($enable_autoservername) +if test "$enable_autoservername" = "yes"; then + AC_DEFINE(FEAT_AUTOSERVERNAME) +fi + +AC_MSG_CHECKING(--enable-multibyte argument) +AC_ARG_ENABLE(multibyte, + [ --enable-multibyte Include multibyte editing support.], , + [enable_multibyte="yes"]) +AC_MSG_RESULT($enable_multibyte) +if test "$enable_multibyte" != "yes"; then + AC_MSG_ERROR([The multi-byte feature can no longer be disabled. If you have + a problem with this, discuss on the Vim mailing list.]) +fi + +dnl Right-to-Left language support for Vim will be included with huge features, +dnl unless ENABLE_RIGHTLEFT is undefined. +AC_MSG_CHECKING(--disable-rightleft argument) +AC_ARG_ENABLE(rightleft, + [ --disable-rightleft Do not include Right-to-Left language support.], + , [enable_rightleft="yes"]) +if test "$enable_rightleft" = "yes"; then + AC_MSG_RESULT(no) +else + AC_MSG_RESULT(yes) + AC_DEFINE(DISABLE_RIGHTLEFT) +fi + +dnl Arabic language support for Vim will be included with huge features, +dnl unless ENABLE_ARABIC is undefined. +AC_MSG_CHECKING(--disable-arabic argument) +AC_ARG_ENABLE(arabic, + [ --disable-arabic Do not include Arabic language support.], + , [enable_arabic="yes"]) +if test "$enable_arabic" = "yes"; then + AC_MSG_RESULT(no) +else + AC_MSG_RESULT(yes) + AC_DEFINE(DISABLE_ARABIC) +fi + +dnl Farsi language support has been removed, ignore --disable-farsi +AC_ARG_ENABLE(farsi, + [ --disable-farsi Deprecated.],,) + +AC_MSG_CHECKING(--enable-xim argument) +AC_ARG_ENABLE(xim, + [ --enable-xim Include XIM input support.], + AC_MSG_RESULT($enable_xim), + [enable_xim="auto"; AC_MSG_RESULT(defaulting to auto)]) + +AC_MSG_CHECKING(--enable-fontset argument) +AC_ARG_ENABLE(fontset, + [ --enable-fontset Include X fontset output support.], , + [enable_fontset="no"]) +AC_MSG_RESULT($enable_fontset) +dnl defining FEAT_XFONTSET is delayed, so that it can be disabled for no GUI + +test -z "$with_x" && with_x=yes +test "${enable_gui-yes}" != no -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && with_x=yes +if test "$with_x" = no; then + AC_MSG_RESULT(defaulting to: don't HAVE_X11) +else + dnl Do this check early, so that its failure can override user requests. + + AC_PATH_PROG(xmkmfpath, xmkmf) + + AC_PATH_XTRA + + dnl On z/OS Unix the X libraries are DLLs. To use them the code must + dnl be compiled with a special option. + dnl Also add SM, ICE and Xmu to X_EXTRA_LIBS. + if test "$zOSUnix" = "yes"; then + CFLAGS="$CFLAGS -W c,dll" + LDFLAGS="$LDFLAGS -W l,dll" + X_EXTRA_LIBS="$X_EXTRA_LIBS -lSM -lICE -lXmu" + fi + + dnl On my HPUX system the X include dir is found, but the lib dir not. + dnl This is a desperate try to fix this. + + if test -d "$x_includes" && test ! -d "$x_libraries"; then + x_libraries=`echo "$x_includes" | sed s/include/lib/` + AC_MSG_RESULT(Corrected X libraries to $x_libraries) + X_LIBS="$X_LIBS -L$x_libraries" + if test "$vim_cv_uname_output" = SunOS && + echo $vim_cv_uname_r_output | grep '^5' >/dev/null; then + X_LIBS="$X_LIBS -R $x_libraries" + fi + fi + + if test -d "$x_libraries" && test ! -d "$x_includes"; then + x_includes=`echo "$x_libraries" | sed s/lib/include/` + AC_MSG_RESULT(Corrected X includes to $x_includes) + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + dnl Remove "-I/usr/include " from X_CFLAGS, should not be needed. + X_CFLAGS="`echo $X_CFLAGS\ | sed 's%-I/usr/include %%'`" + dnl Remove "-L/usr/lib " from X_LIBS, should not be needed. + X_LIBS="`echo $X_LIBS\ | sed 's%-L/usr/lib %%'`" + dnl Same for "-R/usr/lib ". + X_LIBS="`echo $X_LIBS\ | sed -e 's%-R/usr/lib %%' -e 's%-R /usr/lib %%'`" + + + dnl Check if the X11 header files are correctly installed. On some systems + dnl Xlib.h includes files that don't exist. On some systems X11/Intrinsic.h + dnl is missing. + AC_MSG_CHECKING(if X11 header files can be found) + cflags_save=$CFLAGS + CFLAGS="$CFLAGS $X_CFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include +#include ], )], + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no); no_x=yes) + CFLAGS=$cflags_save + + if test "${no_x-no}" = yes; then + with_x=no + else + AC_DEFINE(HAVE_X11) + X_LIB="-lXt -lX11"; + AC_SUBST(X_LIB) + + ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="-L$x_libraries $LDFLAGS" + + dnl Check for -lXdmcp (needed on SunOS 4.1.4) + dnl For HP-UX 10.20 it must be before -lSM -lICE + AC_CHECK_LIB(Xdmcp, _XdmcpAuthDoIt, [X_EXTRA_LIBS="$X_EXTRA_LIBS -lXdmcp"],, + [-lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lXdmcp]) + + dnl Some systems need -lnsl -lsocket when testing for ICE. + dnl The check above doesn't do this, try here (again). Also needed to get + dnl them after Xdmcp. link.sh will remove them when not needed. + dnl Check for other function than above to avoid the cached value + AC_CHECK_LIB(ICE, IceOpenConnection, + [X_EXTRA_LIBS="$X_EXTRA_LIBS -lSM -lICE"],, [$X_EXTRA_LIBS]) + + dnl Check for -lXpm (needed for some versions of Motif) + LDFLAGS="$X_LIBS $ac_save_LDFLAGS" + AC_CHECK_LIB(Xpm, XpmCreatePixmapFromData, [X_PRE_LIBS="$X_PRE_LIBS -lXpm"],, + [-lXt $X_PRE_LIBS -lXpm -lX11 $X_EXTRA_LIBS]) + + dnl Check that the X11 header files don't use implicit declarations + AC_MSG_CHECKING(if X11 header files implicitly declare return values) + cflags_save=$CFLAGS + dnl -Werror is GCC only, others like Solaris Studio might not like it + if test "$GCC" = yes; then + CFLAGS="$CFLAGS $X_CFLAGS -Werror" + else + CFLAGS="$CFLAGS $X_CFLAGS" + fi + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], )], + AC_MSG_RESULT(no), + CFLAGS="$CFLAGS -Wno-implicit-int" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], )], + AC_MSG_RESULT(yes); cflags_save="$cflags_save -Wno-implicit-int", + AC_MSG_RESULT(test failed) + ) + ) + CFLAGS=$cflags_save + + LDFLAGS="$ac_save_LDFLAGS" + + AC_MSG_CHECKING(size of wchar_t is 2 bytes) + AC_CACHE_VAL(ac_cv_small_wchar_t, + [AC_RUN_IFELSE([AC_LANG_SOURCE([ +#include +#if STDC_HEADERS +# include +# include +#endif + int main() + { + if (sizeof(wchar_t) <= 2) + exit(1); + exit(0); + }])], + ac_cv_small_wchar_t="no", + ac_cv_small_wchar_t="yes", + AC_MSG_ERROR(failed to compile test program))]) + AC_MSG_RESULT($ac_cv_small_wchar_t) + if test "x$ac_cv_small_wchar_t" = "xyes" ; then + AC_DEFINE(SMALL_WCHAR_T) + fi + + fi +fi + +dnl Check if --with-x was given but it doesn't work. +if test "x$with_x" = xno -a "x$with_x_arg" = xyes; then + AC_MSG_ERROR([could not configure X]) +fi + +test "x$with_x" = xno -a "x$HAIKU" != "xyes" -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && enable_gui=no + +AC_MSG_CHECKING(--enable-gui argument) +AC_ARG_ENABLE(gui, + [ --enable-gui[=OPTS] X11 GUI. [default=auto] [OPTS=auto/no/gtk2/gnome2/gtk3/motif/haiku/photon/carbon]], , enable_gui="auto") + +dnl Canonicalize the --enable-gui= argument so that it can be easily compared. +dnl Do not use character classes for portability with old tools. +enable_gui_canon=`echo "_$enable_gui" | \ + sed 's/[[ _+-]]//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` + +dnl Skip everything by default. +SKIP_GTK2=YES +SKIP_GTK3=YES +SKIP_GNOME=YES +SKIP_MOTIF=YES +SKIP_PHOTON=YES +SKIP_HAIKU=YES +GUITYPE=NONE + +if test "x$HAIKU" = "xyes"; then + SKIP_HAIKU= + case "$enable_gui_canon" in + no) AC_MSG_RESULT(no GUI support) + SKIP_HAIKU=YES ;; + yes|"") AC_MSG_RESULT(yes - automatic GUI support) ;; + auto) AC_MSG_RESULT(auto - automatic GUI support) ;; + haiku) AC_MSG_RESULT(Haiku GUI support) ;; + *) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported]) + SKIP_HAIKU=YES ;; + esac +elif test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then + SKIP_PHOTON= + case "$enable_gui_canon" in + no) AC_MSG_RESULT(no GUI support) + SKIP_PHOTON=YES ;; + yes|""|auto) AC_MSG_RESULT(automatic GUI support) + gui_auto=yes ;; + photon) AC_MSG_RESULT(Photon GUI support) ;; + *) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported]) + SKIP_PHOTON=YES ;; + esac + +elif test "x$MACOS_X" = "xyes" -a "x$with_x" = "xno" ; then + case "$enable_gui_canon" in + no) AC_MSG_RESULT(no GUI support) ;; + yes|"") AC_MSG_RESULT(yes - automatic GUI support) + gui_auto=yes ;; + auto) AC_MSG_RESULT(auto - disable GUI support for Mac OS) ;; + *) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported]) ;; + esac +else + + case "$enable_gui_canon" in + no|none) AC_MSG_RESULT(no GUI support) ;; + yes|""|auto) AC_MSG_RESULT(yes/auto - automatic GUI support) + gui_auto=yes + SKIP_GTK2= + SKIP_GTK3= + SKIP_GNOME= + SKIP_MOTIF=;; + gtk2) AC_MSG_RESULT(GTK+ 2.x GUI support) + SKIP_GTK2=;; + gnome2) AC_MSG_RESULT(GNOME 2.x GUI support) + SKIP_GNOME= + SKIP_GTK2=;; + gtk3) AC_MSG_RESULT(GTK+ 3.x GUI support) + SKIP_GTK3=;; + motif) AC_MSG_RESULT(Motif GUI support) + SKIP_MOTIF=;; + *) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported]) ;; + esac + +fi + +if test "x$SKIP_GTK2" != "xYES" -a "$enable_gui_canon" != "gtk2" \ + -a "$enable_gui_canon" != "gnome2"; then + AC_MSG_CHECKING(whether or not to look for GTK+ 2) + AC_ARG_ENABLE(gtk2-check, + [ --enable-gtk2-check If auto-select GUI, check for GTK+ 2 [default=yes]], + , enable_gtk2_check="yes") + AC_MSG_RESULT($enable_gtk2_check) + if test "x$enable_gtk2_check" = "xno"; then + SKIP_GTK2=YES + SKIP_GNOME=YES + fi +fi + +if test "x$SKIP_GNOME" != "xYES" -a "$enable_gui_canon" != "gnome2"; then + AC_MSG_CHECKING(whether or not to look for GNOME) + AC_ARG_ENABLE(gnome-check, + [ --enable-gnome-check If GTK GUI, check for GNOME [default=no]], + , enable_gnome_check="no") + AC_MSG_RESULT($enable_gnome_check) + if test "x$enable_gnome_check" = "xno"; then + SKIP_GNOME=YES + fi +fi + +if test "x$SKIP_GTK3" != "xYES" -a "$enable_gui_canon" != "gtk3"; then + AC_MSG_CHECKING(whether or not to look for GTK+ 3) + AC_ARG_ENABLE(gtk3-check, + [ --enable-gtk3-check If auto-select GUI, check for GTK+ 3 [default=yes]], + , enable_gtk3_check="yes") + AC_MSG_RESULT($enable_gtk3_check) + if test "x$enable_gtk3_check" = "xno"; then + SKIP_GTK3=YES + fi +fi + +if test "x$SKIP_MOTIF" != "xYES" -a "$enable_gui_canon" != "motif"; then + AC_MSG_CHECKING(whether or not to look for Motif) + AC_ARG_ENABLE(motif-check, + [ --enable-motif-check If auto-select GUI, check for Motif [default=yes]], + , enable_motif_check="yes") + AC_MSG_RESULT($enable_motif_check) + if test "x$enable_motif_check" = "xno"; then + SKIP_MOTIF=YES + fi +fi + +dnl define an autoconf function to check for a specified version of GTK, and +dnl try to compile/link a GTK program. +dnl +dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for GTK, and define GTK_CFLAGS, GTK_LIBDIR and GTK_LIBS +dnl +AC_DEFUN(AM_PATH_GTK, +[ + if test "X$GTK_CONFIG" != "Xno" -o "X$PKG_CONFIG" != "Xno"; then + { + no_gtk="" + if (test "X$SKIP_GTK2" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ + && $PKG_CONFIG --exists gtk+-2.0; then + { + min_gtk_version=ifelse([$1], ,2.2.0,$1) + AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) + dnl We should be using PKG_CHECK_MODULES() instead of this hack. + dnl But I guess the dependency on pkgconfig.m4 is not wanted or + dnl something like that. + GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-2.0` + GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-2.0` + GTK_LIBS=`$PKG_CONFIG --libs gtk+-2.0` + gtk_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + gtk_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + gtk_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + } + elif (test "X$SKIP_GTK3" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ + && $PKG_CONFIG --exists gtk+-3.0; then + { + min_gtk_version=ifelse([$1], ,3.0.0,$1) + AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) + + GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-3.0` + GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-3.0` + GTK_LIBS=`$PKG_CONFIG --libs gtk+-3.0` + gtk_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + gtk_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + gtk_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + } + else + dnl Put some text before the "no" to hint at installing the gtk-dev + dnl packages. + AC_MSG_CHECKING(for GTK -dev package) + no_gtk=yes + fi + + if test "x$enable_gtktest" = "xyes" -a "x$no_gtk" = "x"; then + { + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + + dnl + dnl Now check if the installed GTK is sufficiently new. + dnl + rm -f conf.gtktest + AC_RUN_IFELSE([AC_LANG_SOURCE([ +#include +#include +#if STDC_HEADERS +# include +# include +#endif + +int +main () +{ +int major, minor, micro; +char *tmp_version; + +system ("touch conf.gtktest"); + +/* HP/UX 9 (%@#!) writes to sscanf strings */ +tmp_version = g_strdup("$min_gtk_version"); +if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_gtk_version"); + exit(1); + } + +if ((gtk_major_version > major) || + ((gtk_major_version == major) && (gtk_minor_version > minor)) || + ((gtk_major_version == major) && (gtk_minor_version == minor) && + (gtk_micro_version >= micro))) +{ + return 0; +} +return 1; +} +])],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + } + fi + if test "x$no_gtk" = x ; then + if test "x$enable_gtktest" = "xyes"; then + AC_MSG_RESULT(yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version) + else + AC_MSG_RESULT(found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version) + fi + ifelse([$2], , :, [$2]) + else + { + AC_MSG_RESULT(no) + GTK_CFLAGS="" + GTK_LIBS="" + ifelse([$3], , :, [$3]) + if test "$fail_if_missing" = "yes" -a "X$gui_auto" != "Xyes"; then + AC_MSG_ERROR([could not configure GTK]) + fi + } + fi + } + else + GTK_CFLAGS="" + GTK_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GTK_CFLAGS) + AC_SUBST(GTK_LIBS) + rm -f conf.gtktest +]) + +dnl --------------------------------------------------------------------------- +dnl gnome +dnl --------------------------------------------------------------------------- +AC_DEFUN([GNOME_INIT_HOOK], +[ + AC_SUBST(GNOME_LIBS) + AC_SUBST(GNOME_LIBDIR) + AC_SUBST(GNOME_INCLUDEDIR) + + AC_ARG_WITH(gnome-includes, + [ --with-gnome-includes=DIR Specify location of GNOME headers], + [CFLAGS="$CFLAGS -I$withval"] + ) + + AC_ARG_WITH(gnome-libs, + [ --with-gnome-libs=DIR Specify location of GNOME libs], + [LDFLAGS="$LDFLAGS -L$withval" gnome_prefix=$withval] + ) + + AC_ARG_WITH(gnome, + [ --with-gnome Specify prefix for GNOME files], + if test x$withval = xyes; then + want_gnome=yes + ifelse([$1], [], :, [$1]) + else + if test "x$withval" = xno; then + want_gnome=no + else + want_gnome=yes + LDFLAGS="$LDFLAGS -L$withval/lib" + CFLAGS="$CFLAGS -I$withval/include" + gnome_prefix=$withval/lib + fi + fi, + want_gnome=yes) + + if test "x$want_gnome" = xyes; then + { + AC_MSG_CHECKING(for libgnomeui-2.0) + if $PKG_CONFIG --exists libgnomeui-2.0; then + AC_MSG_RESULT(yes) + GNOME_LIBS=`$PKG_CONFIG --libs-only-l libgnomeui-2.0` + GNOME_LIBDIR=`$PKG_CONFIG --libs-only-L libgnomeui-2.0` + GNOME_INCLUDEDIR=`$PKG_CONFIG --cflags libgnomeui-2.0` + + dnl On FreeBSD we need -pthread but pkg-config doesn't include it. + dnl This might not be the right way but it works for me... + AC_MSG_CHECKING(for FreeBSD) + if test "$vim_cv_uname_output" = FreeBSD; then + AC_MSG_RESULT(yes, adding -pthread) + GNOME_INCLUDEDIR="$GNOME_INCLUDEDIR -D_THREAD_SAFE" + GNOME_LIBS="$GNOME_LIBS -pthread" + else + AC_MSG_RESULT(no) + fi + $1 + else + AC_MSG_RESULT(not found) + if test "x$2" = xfail; then + AC_MSG_ERROR(Could not find libgnomeui-2.0 via pkg-config) + fi + fi + } + fi +]) + +AC_DEFUN([GNOME_INIT],[ + GNOME_INIT_HOOK([],fail) +]) + +if test "X$PKG_CONFIG" = "X"; then + AC_PATH_TOOL(PKG_CONFIG, pkg-config, no) +fi + + +dnl --------------------------------------------------------------------------- +dnl Check for GTK2. If it fails, then continue on for Motif as before... +dnl --------------------------------------------------------------------------- +if test -z "$SKIP_GTK2"; then + + AC_MSG_CHECKING(--disable-gtktest argument) + AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program], + , enable_gtktest=yes) + if test "x$enable_gtktest" = "xyes" ; then + AC_MSG_RESULT(gtk test enabled) + else + AC_MSG_RESULT(gtk test disabled) + fi + + if test "x$PKG_CONFIG" != "xno"; then + dnl First try finding version 2.2.0 or later. The 2.0.x series has + dnl problems (bold fonts, --remote doesn't work). + dnl Disable checking for GTK3 here, otherwise it's found when GTK2 is not + dnl found. + save_skip_gtk3=$SKIP_GTK3 + SKIP_GTK3=YES + AM_PATH_GTK(2.2.0, + [GUI_LIB_LOC="$GTK_LIBDIR" + GTK_LIBNAME="$GTK_LIBS" + GUI_INC_LOC="$GTK_CFLAGS"], ) + if test "x$GTK_CFLAGS" != "x"; then + SKIP_GTK3=YES + SKIP_MOTIF=YES + GUITYPE=GTK + AC_SUBST(GTK_LIBNAME) + else + SKIP_GTK3=$save_skip_gtk3 + fi + fi + if test "x$GUITYPE" = "xGTK"; then + dnl + dnl if GTK exists, then check for GNOME. + dnl + if test -z "$SKIP_GNOME"; then + { + GNOME_INIT_HOOK([have_gnome=yes]) + if test "x$have_gnome" = xyes ; then + AC_DEFINE(FEAT_GUI_GNOME) + GUI_INC_LOC="$GUI_INC_LOC $GNOME_INCLUDEDIR" + GTK_LIBNAME="$GTK_LIBNAME $GNOME_LIBDIR $GNOME_LIBS" + fi + } + fi + fi +fi + + +dnl --------------------------------------------------------------------------- +dnl Check for GTK3. +dnl --------------------------------------------------------------------------- +if test -z "$SKIP_GTK3"; then + + AC_MSG_CHECKING(--disable-gtktest argument) + AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program], + , enable_gtktest=yes) + if test "x$enable_gtktest" = "xyes" ; then + AC_MSG_RESULT(gtk test enabled) + else + AC_MSG_RESULT(gtk test disabled) + fi + + if test "x$PKG_CONFIG" != "xno"; then + save_skip_gtk2=$SKIP_GTK2 + SKIP_GTK2=YES + AM_PATH_GTK(3.0.0, + [GUI_LIB_LOC="$GTK_LIBDIR" + GTK_LIBNAME="$GTK_LIBS" + GUI_INC_LOC="$GTK_CFLAGS"], ) + if test "x$GTK_CFLAGS" != "x"; then + SKIP_GTK2=YES + SKIP_GNOME=YES + SKIP_MOTIF=YES + GUITYPE=GTK + AC_SUBST(GTK_LIBNAME) + AC_DEFINE(USE_GTK3) + else + SKIP_GTK2=$save_skip_gtk2 + fi + fi +fi + +dnl Check the version of Gdk-Pixbuf. If the version is 2.31 or later and +dnl glib-compile-resources is found in PATH, use GResource. +if test "x$GUITYPE" = "xGTK"; then + AC_MSG_CHECKING([version of Gdk-Pixbuf]) + gdk_pixbuf_version=`$PKG_CONFIG --modversion gdk-pixbuf-2.0` + if test "x$gdk_pixbuf_version" != x ; then + gdk_pixbuf_version_minor=`echo $gdk_pixbuf_version | \ + sed -e 's/[[0-9]][[0-9]]*\.\([[0-9]][[0-9]]*\)\.[[0-9]][[0-9]]*/\1/'` + if test "x$gdk_pixbuf_version_minor" != x -a \ + $gdk_pixbuf_version_minor -ge 31 ; then + AC_MSG_RESULT([OK.]) + AC_PATH_PROG(GLIB_COMPILE_RESOURCES,[glib-compile-resources],no) + AC_MSG_CHECKING([glib-compile-resources]) + if test "x$GLIB_COMPILE_RESOURCES" = xno ; then + GLIB_COMPILE_RESOURCES="" + AC_MSG_RESULT([cannot be found in PATH.]) + else + AC_MSG_RESULT([usable.]) + AC_DEFINE(USE_GRESOURCE) + GRESOURCE_SRC="auto/gui_gtk_gresources.c" + GRESOURCE_OBJ="objects/gui_gtk_gresources.o" + fi + else + AC_MSG_RESULT([not usable.]) + fi + else + AC_MSG_RESULT([cannot obtain from pkg_config.]) + fi + + AC_MSG_CHECKING([--disable-icon-cache-update argument]) + AC_ARG_ENABLE(icon_cache_update, + [ --disable-icon-cache-update update disabled], + [], + [enable_icon_cache_update="yes"]) + if test "$enable_icon_cache_update" = "yes"; then + AC_MSG_RESULT([not set]) + AC_PATH_PROG(GTK_UPDATE_ICON_CACHE,[gtk-update-icon-cache],no) + if test "x$GTK_UPDATE_ICON_CACHE" = "xno" ; then + AC_MSG_RESULT([not found in PATH.]) + fi + else + AC_MSG_RESULT([update disabled]) + fi + + AC_MSG_CHECKING([--disable-desktop-database-update argument]) + AC_ARG_ENABLE(desktop_database_update, + [ --disable-desktop-database-update update disabled], + [], + [enable_desktop_database_update="yes"]) + if test "$enable_desktop_database_update" = "yes"; then + AC_MSG_RESULT([not set]) + AC_PATH_PROG(UPDATE_DESKTOP_DATABASE,[update-desktop-database],no) + if test "x$UPDATE_DESKTOP_DATABASE" = "xno" ; then + AC_MSG_RESULT([not found in PATH.]) + fi + else + AC_MSG_RESULT([update disabled]) + fi +fi +AC_SUBST(GLIB_COMPILE_RESOURCES) +AC_SUBST(GRESOURCE_SRC) +AC_SUBST(GRESOURCE_OBJ) +AC_SUBST(GTK_UPDATE_ICON_CACHE) +AC_SUBST(UPDATE_DESKTOP_DATABASE) + +dnl Check for Motif include files location. +dnl The LAST one found is used, this makes the highest version to be used, +dnl e.g. when Motif1.2 and Motif2.0 are both present. + +if test -z "$SKIP_MOTIF"; then + gui_XXX="/usr/XXX/Motif* /usr/Motif*/XXX /usr/XXX /usr/shlib /usr/X11*/XXX /usr/XXX/X11* /usr/dt/XXX /local/Motif*/XXX /local/XXX/Motif* /usr/local/Motif*/XXX /usr/local/XXX/Motif* /usr/local/XXX /usr/local/X11*/XXX /usr/local/LessTif/Motif*/XXX $MOTIFHOME/XXX" + dnl Remove "-I" from before $GUI_INC_LOC if it's there + GUI_INC_LOC="`echo $GUI_INC_LOC|sed 's%-I%%g'`" + + AC_MSG_CHECKING(for location of Motif GUI includes) + gui_includes="`echo $x_includes|sed 's%/[^/][^/]*$%%'` `echo "$gui_XXX" | sed s/XXX/include/g` $GUI_INC_LOC" + GUI_INC_LOC= + for try in $gui_includes; do + if test -f "$try/Xm/Xm.h"; then + GUI_INC_LOC=$try + fi + done + if test -n "$GUI_INC_LOC"; then + if test "$GUI_INC_LOC" = /usr/include; then + GUI_INC_LOC= + AC_MSG_RESULT(in default path) + else + AC_MSG_RESULT($GUI_INC_LOC) + fi + else + AC_MSG_RESULT() + SKIP_MOTIF=YES + fi +fi + +dnl Check for Motif library files location. In the same order as the include +dnl files, to avoid a mixup if several versions are present + +if test -z "$SKIP_MOTIF"; then + AC_MSG_CHECKING(--with-motif-lib argument) + AC_ARG_WITH(motif-lib, + [ --with-motif-lib=STRING Library for Motif ], + [ MOTIF_LIBNAME="${withval}" ] ) + + if test -n "$MOTIF_LIBNAME"; then + AC_MSG_RESULT($MOTIF_LIBNAME) + GUI_LIB_LOC= + else + AC_MSG_RESULT(no) + + dnl Remove "-L" from before $GUI_LIB_LOC if it's there + GUI_LIB_LOC="`echo $GUI_LIB_LOC|sed 's%-L%%g'`" + + dnl Ubuntu has libXm.so in /usr/lib/i386-linux-gnu and elsewhere. The + dnl linker will figure out which one to use, we only check if one exists. + dnl Cygwin uses the .dll.a extension. + AC_MSG_CHECKING(for location of Motif GUI libs) + gui_libs="`echo $x_libraries|sed 's%/[^/][^/]*$%%'` `echo "$gui_XXX" | sed s/XXX/lib/g` /usr/lib/i386-linux-gnu /usr/lib/x86_64-linux-gnu `echo "$GUI_INC_LOC" | sed s/include/lib/` $GUI_LIB_LOC" + GUI_LIB_LOC= + for try in $gui_libs; do + for libtry in "$try"/libXm.a "$try"/libXm.dll.a "$try"/libXm.so* "$try"/libXm.sl "$try"/libXm.dylib; do + if test -f "$libtry"; then + GUI_LIB_LOC=$try + fi + done + done + if test -n "$GUI_LIB_LOC"; then + dnl Remove /usr/lib, it causes trouble on some systems + if test "$GUI_LIB_LOC" = /usr/lib \ + -o "$GUI_LIB_LOC" = /usr/lib/i386-linux-gnu \ + -o "$GUI_LIB_LOC" = /usr/lib/x86_64-linux-gnu; then + GUI_LIB_LOC= + AC_MSG_RESULT(in default path) + else + if test -n "$GUI_LIB_LOC"; then + AC_MSG_RESULT($GUI_LIB_LOC) + if test "$vim_cv_uname_output" = SunOS && + echo $vim_cv_uname_r_output | grep '^5' >/dev/null; then + GUI_LIB_LOC="$GUI_LIB_LOC -R $GUI_LIB_LOC" + fi + fi + fi + MOTIF_LIBNAME=-lXm + else + AC_MSG_RESULT() + SKIP_MOTIF=YES + fi + fi +fi + +if test -z "$SKIP_MOTIF"; then + GUITYPE=MOTIF + AC_SUBST(MOTIF_LIBNAME) +fi + +if test -z "$SKIP_MOTIF"; then + dnl Prepend -I and -L to $GUI_INC_LOC and $GUI_LIB_LOC if not empty + dnl Avoid adding it when it twice + if test -n "$GUI_INC_LOC"; then + GUI_INC_LOC=-I"`echo $GUI_INC_LOC|sed 's%-I%%'`" + fi + if test -n "$GUI_LIB_LOC"; then + GUI_LIB_LOC=-L"`echo $GUI_LIB_LOC|sed 's%-L%%'`" + fi + + dnl Check for -lXext and then for -lXmu + ldflags_save=$LDFLAGS + LDFLAGS="$X_LIBS $LDFLAGS" + AC_CHECK_LIB(Xext, XShapeQueryExtension, [GUI_X_LIBS="-lXext"],, + [-lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS]) + dnl For Solaris we need -lw and -ldl before linking with -lXmu works. + AC_CHECK_LIB(w, wslen, [X_EXTRA_LIBS="$X_EXTRA_LIBS -lw"],, + [$GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS]) + AC_CHECK_LIB(dl, dlsym, [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldl"],, + [$GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS]) + AC_CHECK_LIB(Xmu, XmuCreateStippledPixmap, [GUI_X_LIBS="-lXmu $GUI_X_LIBS"],, + [$GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS]) + if test -z "$SKIP_MOTIF"; then + AC_CHECK_LIB(Xp, XpEndJob, [GUI_X_LIBS="-lXp $GUI_X_LIBS"],, + [$GUI_X_LIBS -lXm -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS]) + fi + LDFLAGS=$ldflags_save + + dnl Execute xmkmf to figure out if -DNARROWPROTO is needed. + AC_MSG_CHECKING(for extra X11 defines) + NARROW_PROTO= + rm -fr conftestdir + if mkdir conftestdir; then + cd conftestdir + cat > Imakefile <<'EOF' +acfindx: + @echo 'NARROW_PROTO="${PROTO_DEFINES}"' +EOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + fi + cd .. + rm -fr conftestdir + fi + if test -z "$NARROW_PROTO"; then + AC_MSG_RESULT(no) + else + AC_MSG_RESULT($NARROW_PROTO) + fi + AC_SUBST(NARROW_PROTO) +fi + +dnl Look for XSMP support - but don't necessarily restrict it to X11 GUIs +dnl use the X11 include path +if test "$enable_xsmp" = "yes"; then + cppflags_save=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + AC_CHECK_HEADERS(X11/SM/SMlib.h) + CPPFLAGS=$cppflags_save +fi + + +if test -z "$SKIP_MOTIF" -o -z "$SKIP_GTK2" -o -z "$SKIP_GTK3"; then + dnl Check for X11/xpm.h and X11/Sunkeysym.h with the GUI include path + cppflags_save=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + AC_CHECK_HEADERS(X11/xpm.h X11/Sunkeysym.h) + + dnl automatically disable XIM when XIMtext isn't in X11/Xlib.h + if test ! "$enable_xim" = "no"; then + AC_MSG_CHECKING(for XIMText in X11/Xlib.h) + AC_EGREP_CPP(XIMText, [#include ], + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no; xim has been disabled); enable_xim="no") + fi + CPPFLAGS=$cppflags_save + + dnl automatically enable XIM in the GUI + if test "$enable_xim" = "auto" -a "x$GUITYPE" != "xNONE" ; then + AC_MSG_RESULT(X GUI selected; xim has been enabled) + enable_xim="yes" + fi +fi + +if test -z "$SKIP_MOTIF"; then + cppflags_save=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $X_CFLAGS" +dnl Xmu/Editres.h may exist but can only be used after including Intrinsic.h + AC_MSG_CHECKING([for X11/Xmu/Editres.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include +#include ], + [int i; i = 0;])], + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_X11_XMU_EDITRES_H), + AC_MSG_RESULT(no)) + CPPFLAGS=$cppflags_save +fi + +dnl Only use the Xm directory when compiling Motif. +if test -z "$SKIP_MOTIF"; then + cppflags_save=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + if test "$zOSUnix" = "yes"; then + AC_CHECK_HEADERS(Xm/Xm.h) + else + AC_CHECK_HEADERS(Xm/Xm.h Xm/XpmP.h Xm/JoinSideT.h Xm/TraitP.h Xm/Manager.h Xm/UnhighlightT.h Xm/Notebook.h) + fi + + if test "x$ac_cv_header_Xm_XpmP_h" = "xyes"; then + dnl Solaris uses XpmAttributes_21, very annoying. + AC_MSG_CHECKING([for XpmAttributes_21 in Xm/XpmP.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], [XpmAttributes_21 attr;])], + AC_MSG_RESULT(yes); AC_DEFINE(XPMATTRIBUTES_TYPE, XpmAttributes_21), + AC_MSG_RESULT(no); AC_DEFINE(XPMATTRIBUTES_TYPE, XpmAttributes) + ) + else + AC_DEFINE(XPMATTRIBUTES_TYPE, XpmAttributes) + fi + CPPFLAGS=$cppflags_save +fi + +if test "x$GUITYPE" = "xNONE" -a "$enable_xim" = "yes"; then + AC_MSG_RESULT(no GUI selected; xim has been disabled) + enable_xim="no" +fi +if test "x$GUITYPE" = "xNONE" -a "$enable_fontset" = "yes"; then + AC_MSG_RESULT(no GUI selected; fontset has been disabled) + enable_fontset="no" +fi +if test "x$GUITYPE:$enable_fontset" = "xGTK:yes"; then + AC_MSG_RESULT(GTK+ 2 GUI selected; fontset has been disabled) + enable_fontset="no" +fi + +dnl There is no test for the Haiku GUI, if it's selected it's used +if test -z "$SKIP_HAIKU"; then + GUITYPE=HAIKUGUI +fi + +if test -z "$SKIP_PHOTON"; then + GUITYPE=PHOTONGUI +fi + +AC_SUBST(GUI_INC_LOC) +AC_SUBST(GUI_LIB_LOC) +AC_SUBST(GUITYPE) +AC_SUBST(GUI_X_LIBS) + +if test "$enable_workshop" = "yes" -a -n "$SKIP_MOTIF"; then + AC_MSG_ERROR([cannot use workshop without Motif]) +fi + +dnl defining FEAT_XIM and FEAT_XFONTSET is delayed, so that they can be disabled +if test "$enable_xim" = "yes"; then + AC_DEFINE(FEAT_XIM) +fi +if test "$enable_fontset" = "yes"; then + AC_DEFINE(FEAT_XFONTSET) +fi + + +dnl --------------------------------------------------------------------------- +dnl end of GUI-checking +dnl --------------------------------------------------------------------------- + +AC_MSG_CHECKING([for /proc link to executable]) +if test -L "/proc/self/exe"; then + dnl Linux + AC_MSG_RESULT([/proc/self/exe]) + AC_DEFINE(PROC_EXE_LINK, "/proc/self/exe") +elif test -L "/proc/self/path/a.out"; then + dnl Solaris + AC_MSG_RESULT([/proc/self/path/a.out]) + AC_DEFINE(PROC_EXE_LINK, "/proc/self/path/a.out") +elif test -L "/proc/curproc/file"; then + dnl FreeBSD + AC_MSG_RESULT([/proc/curproc/file]) + AC_DEFINE(PROC_EXE_LINK, "/proc/curproc/file") +else + AC_MSG_RESULT(no) +fi + +dnl Check for Cygwin, which needs an extra source file if not using X11 +AC_MSG_CHECKING(for CYGWIN or MSYS environment) +case $vim_cv_uname_output in + CYGWIN*|MSYS*) CYGWIN=yes; AC_MSG_RESULT(yes) + AC_MSG_CHECKING(for CYGWIN clipboard support) + if test "x$with_x" = "xno" ; then + OS_EXTRA_SRC=winclip.c; OS_EXTRA_OBJ=objects/winclip.o + AC_MSG_RESULT(yes) + AC_DEFINE(FEAT_CYGWIN_WIN32_CLIPBOARD) + else + AC_MSG_RESULT(no - using X11) + fi ;; + + *) CYGWIN=no; AC_MSG_RESULT(no);; +esac + +dnl Checks for libraries and include files. + +AC_CACHE_CHECK([whether toupper is broken], [vim_cv_toupper_broken], + [ + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include "confdefs.h" +#include +#if STDC_HEADERS +# include +# include +#endif +int main() { exit(toupper('A') == 'A' && tolower('z') == 'z'); } + ]])],[ + vim_cv_toupper_broken=yes + ],[ + vim_cv_toupper_broken=no + ],[ + AC_MSG_ERROR(cross-compiling: please set 'vim_cv_toupper_broken') + ])]) + +if test "x$vim_cv_toupper_broken" = "xyes" ; then + AC_DEFINE(BROKEN_TOUPPER) +fi + +AC_MSG_CHECKING(whether __DATE__ and __TIME__ work) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], [printf("(" __DATE__ " " __TIME__ ")");])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_DATE_TIME), + AC_MSG_RESULT(no)) + +AC_MSG_CHECKING(whether __attribute__((unused)) is allowed) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], [int x __attribute__((unused));])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ATTRIBUTE_UNUSED), + AC_MSG_RESULT(no)) + +dnl Checks for header files. +AC_CHECK_HEADER(elf.h, HAS_ELF=1) +dnl AC_CHECK_HEADER(dwarf.h, SVR4=1) +if test "$HAS_ELF" = 1; then + AC_CHECK_LIB(elf, main) +fi + +AC_HEADER_DIRENT + +dnl If sys/wait.h is not found it might still exist but not be POSIX +dnl compliant. In that case we define HAVE_UNION_WAIT (for NeXT) +if test $ac_cv_header_sys_wait_h = no; then + AC_MSG_CHECKING([for sys/wait.h that defines union wait]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], + [union wait xx, yy; xx = yy])], + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SYS_WAIT_H) + AC_DEFINE(HAVE_UNION_WAIT), + AC_MSG_RESULT(no)) +fi + +AC_CHECK_HEADERS(stdint.h stdlib.h string.h \ + sys/select.h sys/utsname.h termcap.h fcntl.h \ + sgtty.h sys/ioctl.h sys/time.h sys/types.h \ + termio.h iconv.h inttypes.h langinfo.h math.h \ + unistd.h stropts.h errno.h sys/resource.h \ + sys/systeminfo.h locale.h sys/stream.h termios.h \ + libc.h sys/statfs.h poll.h sys/poll.h pwd.h \ + utime.h sys/param.h sys/ptms.h libintl.h libgen.h \ + util/debug.h util/msg18n.h frame.h sys/acl.h \ + sys/access.h sys/sysinfo.h wchar.h wctype.h) + +dnl sys/ptem.h depends on sys/stream.h on Solaris +AC_CHECK_HEADERS(sys/ptem.h, [], [], +[#if defined HAVE_SYS_STREAM_H +# include +#endif]) + +dnl sys/sysctl.h depends on sys/param.h on OpenBSD +AC_CHECK_HEADERS(sys/sysctl.h, [], [], +[#if defined HAVE_SYS_PARAM_H +# include +#endif]) + + +dnl pthread_np.h may exist but can only be used after including pthread.h +AC_MSG_CHECKING([for pthread_np.h]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include +#include ], + [int i; i = 0;])], + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PTHREAD_NP_H), + AC_MSG_RESULT(no)) + +AC_CHECK_HEADERS(strings.h) +if test "x$MACOS_X" = "xyes"; then + dnl The strings.h file on OS/X contains a warning and nothing useful. + AC_DEFINE(NO_STRINGS_WITH_STRING_H) +else + +dnl Check if strings.h and string.h can both be included when defined. +AC_MSG_CHECKING([if strings.h can be included after string.h]) +cppflags_save=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $X_CFLAGS" +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#if defined(_AIX) && !defined(_AIX51) && !defined(_NO_PROTO) +# define _NO_PROTO /* like in os_unix.h, causes conflict for AIX (Winn) */ + /* but don't do it on AIX 5.1 (Uribarri) */ +#endif +#ifdef HAVE_XM_XM_H +# include /* This breaks it for HP-UX 11 (Squassabia) */ +#endif +#ifdef HAVE_STRING_H +# include +#endif +#if defined(HAVE_STRINGS_H) +# include +#endif + ], [int i; i = 0;])], + AC_MSG_RESULT(yes), + AC_DEFINE(NO_STRINGS_WITH_STRING_H) + AC_MSG_RESULT(no)) +CPPFLAGS=$cppflags_save +fi + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_PROG_GCC_TRADITIONAL +AC_C_CONST +AC_C_VOLATILE +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_UID_T +AC_TYPE_UINT32_T + +AC_HEADER_TIME +AC_CHECK_TYPE(ino_t, long) +AC_CHECK_TYPE(dev_t, unsigned) +AC_C_BIGENDIAN(,,,) +AC_C_INLINE + +AC_MSG_CHECKING(for rlim_t) +if eval "test \"`echo '$''{'ac_cv_type_rlim_t'+set}'`\" = set"; then + AC_MSG_RESULT([(cached) $ac_cv_type_rlim_t]) +else + AC_EGREP_CPP(dnl +changequote(<<,>>)dnl +<<(^|[^a-zA-Z_0-9])rlim_t[^a-zA-Z_0-9]>>dnl +changequote([,]), + [ +#include +#if STDC_HEADERS +# include +# include +#endif +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif + ], ac_cv_type_rlim_t=yes, ac_cv_type_rlim_t=no) + AC_MSG_RESULT($ac_cv_type_rlim_t) +fi +if test $ac_cv_type_rlim_t = no; then + cat >> confdefs.h <<\EOF +#define rlim_t unsigned long +EOF +fi + +AC_MSG_CHECKING(for stack_t) +if eval "test \"`echo '$''{'ac_cv_type_stack_t'+set}'`\" = set"; then + AC_MSG_RESULT([(cached) $ac_cv_type_stack_t]) +else + AC_EGREP_CPP(stack_t, + [ +#include +#if STDC_HEADERS +# include +# include +#endif +#include + ], ac_cv_type_stack_t=yes, ac_cv_type_stack_t=no) + AC_MSG_RESULT($ac_cv_type_stack_t) +fi +if test $ac_cv_type_stack_t = no; then + cat >> confdefs.h <<\EOF +#define stack_t struct sigaltstack +EOF +fi + +dnl BSDI uses ss_base while others use ss_sp for the stack pointer. +AC_MSG_CHECKING(whether stack_t has an ss_base field) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include +#if STDC_HEADERS +# include +# include +#endif +#include +#include "confdefs.h" + ], [stack_t sigstk; sigstk.ss_base = 0; ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SS_BASE), + AC_MSG_RESULT(no)) + +olibs="$LIBS" +AC_MSG_CHECKING(--with-tlib argument) +AC_ARG_WITH(tlib, [ --with-tlib=library terminal library to be used ],) +if test -n "$with_tlib"; then + AC_MSG_RESULT($with_tlib) + LIBS="$LIBS -l$with_tlib" + AC_MSG_CHECKING(for linking with $with_tlib library) + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], AC_MSG_RESULT(OK), AC_MSG_ERROR(FAILED)) + dnl Need to check for tgetent() below. + olibs="$LIBS" +else + AC_MSG_RESULT([empty: automatic terminal library selection]) + dnl On HP-UX 10.10 termcap or termlib should be used instead of + dnl curses, because curses is much slower. + dnl Newer versions of ncurses are preferred over anything, except + dnl when tinfo has been split off, it contains all we need. + dnl Older versions of ncurses have bugs, get a new one! + dnl Digital Unix (OSF1) should use curses (Ronald Schild). + dnl On SCO Openserver should prefer termlib (Roger Cornelius). + case "$vim_cv_uname_output" in + OSF1|SCO_SV) tlibs="tinfo ncurses curses termlib termcap";; + *) tlibs="tinfo ncurses termlib termcap curses";; + esac + for libname in $tlibs; do + AC_CHECK_LIB(${libname}, tgetent,,) + if test "x$olibs" != "x$LIBS"; then + dnl It's possible that a library is found but it doesn't work + dnl e.g., shared library that cannot be found + dnl compile and run a test program to be sure + AC_RUN_IFELSE([AC_LANG_SOURCE([ +#ifdef HAVE_TERMCAP_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif +int main() {char *s; s=(char *)tgoto("%p1%d", 0, 1); exit(0); }])], + res="OK", res="FAIL", res="FAIL") + if test "$res" = "OK"; then + break + fi + AC_MSG_RESULT($libname library is not usable) + LIBS="$olibs" + fi + done + if test "x$olibs" = "x$LIBS"; then + AC_MSG_RESULT(no terminal library found) + fi +fi + +if test "x$olibs" = "x$LIBS"; then + AC_MSG_CHECKING([for tgetent()]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([int tgetent(char *, const char *);], + [[char s[10000]; int res = tgetent(s, "thisterminaldoesnotexist");]])], + AC_MSG_RESULT(yes), + AC_MSG_ERROR([NOT FOUND! + You need to install a terminal library; for example ncurses. + On Linux that would be the libncurses-dev package. + Or specify the name of the library with --with-tlib.])) +fi + +AC_CACHE_CHECK([whether we talk terminfo], [vim_cv_terminfo], + [ + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include "confdefs.h" +#ifdef HAVE_TERMCAP_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif +int main() +{char *s; s=(char *)tgoto("%p1%d", 0, 1); exit(!strcmp(s==0 ? "" : s, "1")); } + ]])],[ + vim_cv_terminfo=no + ],[ + vim_cv_terminfo=yes + ],[ + AC_MSG_ERROR(cross-compiling: please set 'vim_cv_terminfo') + ]) + ]) + +if test "x$vim_cv_terminfo" = "xyes" ; then + AC_DEFINE(TERMINFO) +fi + +AC_CACHE_CHECK([what tgetent() returns for an unknown terminal], [vim_cv_tgetent], + [ + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include "confdefs.h" +#ifdef HAVE_TERMCAP_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif +int main() +{char s[10000]; int res = tgetent(s, "thisterminaldoesnotexist"); exit(res != 0); } + ]])],[ + vim_cv_tgetent=zero + ],[ + vim_cv_tgetent=non-zero + ],[ + AC_MSG_ERROR(failed to compile test program.) + ]) + ]) + +if test "x$vim_cv_tgetent" = "xzero" ; then + AC_DEFINE(TGETENT_ZERO_ERR, 0) +fi + +AC_MSG_CHECKING(whether termcap.h contains ospeed) +AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_TERMCAP_H +# include +#endif + ], [ospeed = 20000])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_OSPEED), + [AC_MSG_RESULT(no) + AC_MSG_CHECKING(whether ospeed can be extern) + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_TERMCAP_H +# include +#endif +extern short ospeed; + ], [ospeed = 20000])], + AC_MSG_RESULT(yes); AC_DEFINE(OSPEED_EXTERN), + AC_MSG_RESULT(no))] + ) + +AC_MSG_CHECKING([whether termcap.h contains UP, BC and PC]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_TERMCAP_H +# include +#endif + ], [if (UP == 0 && BC == 0) PC = 1])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_UP_BC_PC), + [AC_MSG_RESULT(no) + AC_MSG_CHECKING([whether UP, BC and PC can be extern]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_TERMCAP_H +# include +#endif +extern char *UP, *BC, PC; + ], [if (UP == 0 && BC == 0) PC = 1])], + AC_MSG_RESULT(yes); AC_DEFINE(UP_BC_PC_EXTERN), + AC_MSG_RESULT(no))] + ) + +AC_MSG_CHECKING(whether tputs() uses outfuntype) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_TERMCAP_H +# include +#endif + ], [extern int xx(); tputs("test", 1, (outfuntype)xx)])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_OUTFUNTYPE), + AC_MSG_RESULT(no)) + +AC_MSG_CHECKING([whether del_curterm() can be used]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_TERMCAP_H +# include +#endif +#include + ], [if (cur_term) del_curterm(cur_term);])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_DEL_CURTERM), + AC_MSG_RESULT(no)) + +dnl On some SCO machines sys/select redefines struct timeval +AC_MSG_CHECKING([whether sys/select.h and sys/time.h may both be included]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include +#include +#include ], )], + AC_MSG_RESULT(yes) + AC_DEFINE(SYS_SELECT_WITH_SYS_TIME), + AC_MSG_RESULT(no)) + +dnl AC_DECL_SYS_SIGLIST + +dnl Checks for pty.c (copied from screen) ========================== +AC_MSG_CHECKING(for /dev/ptc) +if test -r /dev/ptc; then + AC_DEFINE(HAVE_DEV_PTC) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(for SVR4 ptys) +if test -c /dev/ptmx ; then + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +// These should be in stdlib.h, but it depends on _XOPEN_SOURCE. +char *ptsname(int); +int unlockpt(int); +int grantpt(int); + ], [ + ptsname(0); + grantpt(0); + unlockpt(0);])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SVR4_PTYS), + AC_MSG_RESULT(no)) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(for ptyranges) +if test -d /dev/ptym ; then + pdir='/dev/ptym' +else + pdir='/dev' +fi +dnl SCO uses ptyp%d +AC_EGREP_CPP(yes, +[#ifdef M_UNIX + yes; +#endif + ], ptys=`echo /dev/ptyp??`, ptys=`echo $pdir/pty??`) +dnl if test -c /dev/ptyp19; then +dnl ptys=`echo /dev/ptyp??` +dnl else +dnl ptys=`echo $pdir/pty??` +dnl fi +if test "$ptys" != "$pdir/pty??" ; then + p0=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\).$/\1/g' | sort -u | tr -d '\012'` + p1=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\)$/\1/g' | sort -u | tr -d '\012'` + AC_DEFINE_UNQUOTED(PTYRANGE0,"$p0") + AC_DEFINE_UNQUOTED(PTYRANGE1,"$p1") + AC_MSG_RESULT([$p0 / $p1]) +else + AC_MSG_RESULT([don't know]) +fi + +dnl Checks for library functions. =================================== + +dnl check if struct sigcontext is defined (used for SGI only) +AC_MSG_CHECKING(for struct sigcontext) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include +int test_sig() +{ + struct sigcontext *scont; + scont = (struct sigcontext *)0; + return 1; +} ], )], + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SIGCONTEXT), + AC_MSG_RESULT(no)) + +dnl tricky stuff: try to find out if getcwd() is implemented with +dnl system("sh -c pwd") +AC_CACHE_CHECK([getcwd implementation is broken], [vim_cv_getcwd_broken], + [ + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include "confdefs.h" +#ifdef HAVE_UNISTD_H +#include +#endif +char *dagger[] = { "IFS=pwd", 0 }; +int main() +{ + char buffer[500]; + extern char **environ; + environ = dagger; + return getcwd(buffer, 500) ? 0 : 1; +} + ]])],[ + vim_cv_getcwd_broken=no + ],[ + vim_cv_getcwd_broken=yes + ],[ + AC_MSG_ERROR(cross-compiling: please set 'vim_cv_getcwd_broken') + ]) + ]) + +if test "x$vim_cv_getcwd_broken" = "xyes" ; then + AC_DEFINE(BAD_GETCWD) + AC_CHECK_FUNCS(getwd) +fi + +dnl Check for functions in one big call, to reduce the size of configure. +dnl Can only be used for functions that do not require any include. +AC_CHECK_FUNCS(fchdir fchown fchmod fsync getcwd getpseudotty \ + getpwent getpwnam getpwuid getrlimit gettimeofday localtime_r lstat \ + memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \ + getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \ + sigprocmask sigvec strcasecmp strcoll strerror strftime stricmp strncasecmp \ + strnicmp strpbrk strptime strtol tgetent towlower towupper iswupper \ + tzset usleep utime utimes mblen ftruncate unsetenv posix_openpt) +AC_FUNC_SELECT_ARGTYPES +AC_FUNC_FSEEKO + +dnl define _LARGE_FILES, _FILE_OFFSET_BITS and _LARGEFILE_SOURCE when +dnl appropriate, so that off_t is 64 bits when needed. +AC_SYS_LARGEFILE + +AC_MSG_CHECKING(--enable-canberra argument) +AC_ARG_ENABLE(canberra, + [ --disable-canberra Do not use libcanberra.], + , [enable_canberra="maybe"]) + +if test "$enable_canberra" = "maybe"; then + if test "$features" = "huge"; then + AC_MSG_RESULT(Defaulting to yes) + enable_canberra="yes" + else + AC_MSG_RESULT(Defaulting to no) + enable_canberra="no" + fi +else + if test "$enable_canberra" = "yes" -a "$has_eval" = "no"; then + AC_MSG_RESULT([cannot use sound with tiny features]) + enable_canberra="no" + else + AC_MSG_RESULT($enable_canberra) + fi +fi +if test "$enable_canberra" = "yes"; then + if test "x$PKG_CONFIG" != "xno"; then + canberra_lib=`$PKG_CONFIG --libs libcanberra 2>/dev/null` + canberra_cflags=`$PKG_CONFIG --cflags libcanberra 2>/dev/null` + fi + if test "x$canberra_lib" = "x"; then + canberra_lib=-lcanberra + canberra_cflags=-D_REENTRANT + fi + AC_MSG_CHECKING(for libcanberra) + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + if `echo "$CFLAGS" | grep -v "$canberra_cflags" 2>/dev/null`; then + CFLAGS="$CFLAGS $canberra_cflags" + fi + LIBS="$LIBS $canberra_lib" + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + # include + ], [ + ca_context *hello; + ca_context_create(&hello);])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_CANBERRA), + AC_MSG_RESULT(no; try installing libcanberra-dev); CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS") +fi + +AC_MSG_CHECKING(--enable-libsodium argument) +AC_ARG_ENABLE(libsodium, + [ --disable-libsodium Do not use libsodium.], + , [enable_libsodium="maybe"]) + +if test "$enable_libsodium" = "maybe"; then + if test "$features" = "huge"; then + AC_MSG_RESULT(Defaulting to yes) + enable_libsodium="yes" + else + AC_MSG_RESULT(Defaulting to no) + enable_libsodium="no" + fi +else + AC_MSG_RESULT($enable_libsodium) +fi +if test "$enable_libsodium" = "yes"; then + if test "x$PKG_CONFIG" != "xno"; then + libsodium_lib=`$PKG_CONFIG --libs libsodium 2>/dev/null` + libsodium_cflags=`$PKG_CONFIG --cflags libsodium 2>/dev/null` + fi + if test "x$libsodium_lib" = "x"; then + libsodium_lib=-lsodium + libsodium_cflags= + fi + AC_MSG_CHECKING(for libsodium) + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $libsodium_cflags" + LIBS="$LIBS $libsodium_lib" + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + # include + ], [ + printf("%d", sodium_init()); ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SODIUM), + AC_MSG_RESULT(no; try installing libsodium-dev); CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS") +fi + +dnl fstatfs() can take 2 to 4 arguments, try to use st_blksize if possible +AC_MSG_CHECKING(for st_blksize) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[#include +#include ], +[ struct stat st; + int n; + + stat("/", &st); + n = (int)st.st_blksize;])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ST_BLKSIZE), + AC_MSG_RESULT(no)) + +dnl Check for timer_create. It probably requires the 'rt' library. +dnl Run the program to find out if timer_create(CLOCK_MONOTONIC) actually +dnl works, on Solaris timer_create() exists but fails at runtime. +AC_CACHE_CHECK([for timer_create without -lrt], [vim_cv_timer_create], [ +AC_RUN_IFELSE([AC_LANG_PROGRAM([ +#if STDC_HEADERS +# include +# include +#endif +#include +#include +static void set_flag(union sigval sv) {} +], [ + struct timespec ts; + struct sigevent action = {0}; + timer_t timer_id; + + action.sigev_notify = SIGEV_THREAD; + action.sigev_notify_function = set_flag; + if (timer_create(CLOCK_MONOTONIC, &action, &timer_id) < 0) + exit(1); // cannot create a monotonic timer + ])], + vim_cv_timer_create=yes, + vim_cv_timer_create=no, + AC_MSG_WARN([failed to build test program; if cross-compiling please set 'vim_cv_timer_create']) + )]) + +dnl If the previous failed, check for timer_create() and linking with -lrt. +if test "x$vim_cv_timer_create" = "xno" ; then + save_LIBS="$LIBS" + LIBS="$LIBS -lrt" + AC_CACHE_CHECK([for timer_create with -lrt], [vim_cv_timer_create_with_lrt], [ + AC_RUN_IFELSE([AC_LANG_PROGRAM([ + #if STDC_HEADERS + # include + # include + #endif + #include + #include + static void set_flag(union sigval sv) {} + ], [ + struct timespec ts; + struct sigevent action = {0}; + timer_t timer_id; + + action.sigev_notify = SIGEV_THREAD; + action.sigev_notify_function = set_flag; + if (timer_create(CLOCK_MONOTONIC, &action, &timer_id) < 0) + exit(1); // cannot create a monotonic timer + ])], + vim_cv_timer_create_with_lrt=yes, + vim_cv_timer_create_with_lrt=no, + AC_MSG_WARN([failed to build test program; if cross-compiling please set 'vim_cv_timer_create_with_lrt']) + )]) + LIBS="$save_LIBS" +else + vim_cv_timer_create_with_lrt=no +fi + +if test "x$vim_cv_timer_create" = "xyes" ; then + AC_DEFINE(HAVE_TIMER_CREATE) +fi +if test "x$vim_cv_timer_create_with_lrt" = "xyes" ; then + AC_DEFINE(HAVE_TIMER_CREATE) + LIBS="$LIBS -lrt" +fi + +AC_CACHE_CHECK([whether stat() ignores a trailing slash], [vim_cv_stat_ignores_slash], + [ + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include "confdefs.h" +#if STDC_HEADERS +# include +# include +#endif +#include +#include +int main() {struct stat st; exit(stat("configure/", &st) != 0); } + ]])],[ + vim_cv_stat_ignores_slash=yes + ],[ + vim_cv_stat_ignores_slash=no + ],[ + AC_MSG_ERROR(cross-compiling: please set 'vim_cv_stat_ignores_slash') + ]) + ]) + +if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then + AC_DEFINE(STAT_IGNORES_SLASH) +fi + +dnl nanoseconds field of struct stat +AC_CACHE_CHECK([for nanoseconds field of struct stat], + ac_cv_struct_st_mtim_nsec, + [ac_save_CPPFLAGS="$CPPFLAGS" + ac_cv_struct_st_mtim_nsec=no + # st_mtim.tv_nsec -- the usual case + # st_mtim._tv_nsec -- Solaris 2.6, if + # (defined _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED == 1 + # && !defined __EXTENSIONS__) + # st_mtim.st__tim.tv_nsec -- UnixWare 2.1.2 + # st_mtime_n -- AIX 5.2 and above + # st_mtimespec.tv_nsec -- Darwin (Mac OSX) + for ac_val in st_mtim.tv_nsec st_mtim._tv_nsec st_mtim.st__tim.tv_nsec st_mtime_n st_mtimespec.tv_nsec; do + CPPFLAGS="$ac_save_CPPFLAGS -DST_MTIM_NSEC=$ac_val" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include +#include ], [struct stat s; s.ST_MTIM_NSEC;])], + [ac_cv_struct_st_mtim_nsec=$ac_val; break]) + done + CPPFLAGS="$ac_save_CPPFLAGS" +]) +if test $ac_cv_struct_st_mtim_nsec != no; then + AC_DEFINE_UNQUOTED([ST_MTIM_NSEC], [$ac_cv_struct_st_mtim_nsec], + [Define if struct stat contains a nanoseconds field]) +fi + +dnl Link with iconv for charset translation, if not found without library. +dnl check for iconv() requires including iconv.h +dnl Add "-liconv" when possible; Solaris has iconv but use GNU iconv when it +dnl has been installed. +AC_MSG_CHECKING(for iconv_open()) +save_LIBS="$LIBS" +LIBS="$LIBS -liconv" +AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_ICONV_H +# include +#endif + ], [iconv_open("fr", "to");])], + AC_MSG_RESULT(yes; with -liconv); AC_DEFINE(HAVE_ICONV), + LIBS="$save_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_ICONV_H +# include +#endif + ], [iconv_open("fr", "to");])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ICONV), + AC_MSG_RESULT(no))) + + +AC_MSG_CHECKING(for nl_langinfo(CODESET)) +AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_LANGINFO_H +# include +#endif +], [char *cs = nl_langinfo(CODESET);])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_NL_LANGINFO_CODESET), + AC_MSG_RESULT(no)) + +dnl Floating point support may require the "m" library +AC_CHECK_LIB(m, strtod) + +dnl isinf() and isnan() need to include header files and may need -lm. +AC_MSG_CHECKING([for isinf()]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_MATH_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif +], [int r = isinf(1.11); ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ISINF), + AC_MSG_RESULT(no)) + +AC_MSG_CHECKING([for isnan()]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_MATH_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif +], [int r = isnan(1.11); ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ISNAN), + AC_MSG_RESULT(no)) + +dnl Link with -lposix1e for ACL stuff; if not found, try -lacl for SGI +dnl when -lacl works, also try to use -lattr (required for Debian). +dnl On Solaris, use the acl_get/set functions in libsec, if present. +AC_MSG_CHECKING(--disable-acl argument) +AC_ARG_ENABLE(acl, + [ --disable-acl No check for ACL support.], + , [enable_acl="yes"]) +if test "$enable_acl" = "yes"; then + AC_MSG_RESULT(no) + AC_CHECK_LIB(posix1e, acl_get_file, [LIBS="$LIBS -lposix1e"], + AC_CHECK_LIB(acl, acl_get_file, [LIBS="$LIBS -lacl" + AC_CHECK_LIB(attr, fgetxattr, LIBS="$LIBS -lattr",,)],,),) + + AC_MSG_CHECKING(for POSIX ACL support) + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#include +#ifdef HAVE_SYS_ACL_H +# include +#endif +acl_t acl;], [acl = acl_get_file("foo", ACL_TYPE_ACCESS); + acl_set_file("foo", ACL_TYPE_ACCESS, acl); + acl_free(acl);])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_POSIX_ACL), + AC_MSG_RESULT(no)) + + AC_CHECK_LIB(sec, acl_get, [LIBS="$LIBS -lsec"; AC_DEFINE(HAVE_SOLARIS_ZFS_ACL)], + AC_MSG_CHECKING(for Solaris ACL support) + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_SYS_ACL_H +# include +#endif], [acl("foo", GETACLCNT, 0, NULL); + ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SOLARIS_ACL), + AC_MSG_RESULT(no))) + + AC_MSG_CHECKING(for AIX ACL support) + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#if STDC_HEADERS +# include +# include +#endif +#ifdef HAVE_SYS_ACL_H +# include +#endif +#ifdef HAVE_SYS_ACCESS_H +# include +#endif +#define _ALL_SOURCE + +#include + +int aclsize; +struct acl *aclent;], [aclsize = sizeof(struct acl); + aclent = (void *)malloc(aclsize); + statacl("foo", STX_NORMAL, aclent, aclsize); + ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_AIX_ACL), + AC_MSG_RESULT(no)) +else + AC_MSG_RESULT(yes) +fi + +if test "x$GTK_CFLAGS" != "x"; then + dnl pango_shape_full() is new, fall back to pango_shape(). + AC_MSG_CHECKING(for pango_shape_full) + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [#include ], + [ pango_shape_full(NULL, 0, NULL, 0, NULL, NULL); ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_PANGO_SHAPE_FULL), + AC_MSG_RESULT(no)) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" +fi + +AC_MSG_CHECKING(--enable-gpm argument) +AC_ARG_ENABLE(gpm, + [ --enable-gpm=OPTS Use gpm (Linux mouse daemon). default=yes OPTS=yes/no/dynamic], , + [enable_gpm="yes"]) + +if test "$enable_gpm" = "yes" -o "$enable_gpm" = "dynamic"; then + AC_MSG_RESULT($enable_gpm) + dnl Checking if gpm support can be compiled + AC_CACHE_CHECK([for gpm], vi_cv_have_gpm, + [olibs="$LIBS" ; LIBS="-lgpm"] + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [#include + #include ], + [Gpm_GetLibVersion(NULL);])], + dnl Configure defines HAVE_GPM, if it is defined feature.h defines + dnl FEAT_MOUSE_GPM if mouse support is included + [vi_cv_have_gpm=yes], + [vi_cv_have_gpm=no]) + [LIBS="$olibs"] + ) + if test $vi_cv_have_gpm = yes; then + if test "$enable_gpm" = "yes"; then + LIBS="$LIBS -lgpm" + else + AC_DEFINE(DYNAMIC_GPM) + fi + AC_DEFINE(HAVE_GPM) + fi +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(--disable-sysmouse argument) +AC_ARG_ENABLE(sysmouse, + [ --disable-sysmouse Don't use sysmouse (mouse in *BSD console).], , + [enable_sysmouse="yes"]) + +if test "$enable_sysmouse" = "yes"; then + AC_MSG_RESULT(no) + dnl Checking if sysmouse support can be compiled + dnl Configure defines HAVE_SYSMOUSE, if it is defined feature.h + dnl defines FEAT_SYSMOUSE if mouse support is included + AC_CACHE_CHECK([for sysmouse], vi_cv_have_sysmouse, + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [#include + #include + #include ], + [struct mouse_info mouse; + mouse.operation = MOUSE_MODE; + mouse.operation = MOUSE_SHOW; + mouse.u.mode.mode = 0; + mouse.u.mode.signal = SIGUSR2;])], + [vi_cv_have_sysmouse=yes], + [vi_cv_have_sysmouse=no]) + ) + if test $vi_cv_have_sysmouse = yes; then + AC_DEFINE(HAVE_SYSMOUSE) + fi +else + AC_MSG_RESULT(yes) +fi + +dnl make sure the FD_CLOEXEC flag for fcntl()'s F_SETFD command is known +AC_MSG_CHECKING(for FD_CLOEXEC) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[#if HAVE_FCNTL_H +# include +#endif], +[ int flag = FD_CLOEXEC;])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_FD_CLOEXEC), + AC_MSG_RESULT(not usable)) + +dnl rename needs to be checked separately to work on Nextstep with cc +AC_MSG_CHECKING(for rename) +AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [rename("this", "that")])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_RENAME), + AC_MSG_RESULT(no)) + +dnl check for dirfd() +AC_MSG_CHECKING(for dirfd) +AC_LINK_IFELSE([AC_LANG_PROGRAM( +[#include +#include ], +[DIR * dir=opendir("dirname"); dirfd(dir);])], +AC_MSG_RESULT(yes); AC_DEFINE(HAVE_DIRFD), AC_MSG_RESULT(not usable)) + +dnl check for flock() +AC_MSG_CHECKING(for flock) +AC_LINK_IFELSE([AC_LANG_PROGRAM( +[#include ], +[flock(10, LOCK_SH);])], +AC_MSG_RESULT(yes); AC_DEFINE(HAVE_FLOCK), AC_MSG_RESULT(not usable)) + +dnl sysctl() may exist but not the arguments we use +AC_MSG_CHECKING(for sysctl) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[#include +#include ], +[[ int mib[2], r; + size_t len; + + mib[0] = CTL_HW; + mib[1] = HW_USERMEM; + len = sizeof(r); + (void)sysctl(mib, 2, &r, &len, (void *)0, (size_t)0); + ]])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSCTL), + AC_MSG_RESULT(not usable)) + +dnl sysinfo() may exist but not be Linux compatible. +dnl On some FreeBSD systems it may depend on libsysinfo, try to link +AC_MSG_CHECKING(for sysinfo) +AC_LINK_IFELSE([AC_LANG_PROGRAM( +[#include +#include ], +[ struct sysinfo sinfo; + int t; + + (void)sysinfo(&sinfo); + t = sinfo.totalram; + ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSINFO), + AC_MSG_RESULT(not usable)) + +dnl struct sysinfo may have the mem_unit field or not +AC_MSG_CHECKING(for sysinfo.mem_unit) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[#include +#include ], +[ struct sysinfo sinfo; + sinfo.mem_unit = 1; + ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSINFO_MEM_UNIT), + AC_MSG_RESULT(no)) + +dnl struct sysinfo may have the uptime field or not +AC_MSG_CHECKING(for sysinfo.uptime) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[#include +#include ], +[ struct sysinfo sinfo; + long ut; + + (void)sysinfo(&sinfo); + ut = sinfo.uptime; + ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSINFO_UPTIME), + AC_MSG_RESULT(no)) + +dnl sysconf() may exist but not support what we want to use +AC_MSG_CHECKING(for sysconf) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[#include ], +[ (void)sysconf(_SC_PAGESIZE); + (void)sysconf(_SC_PHYS_PAGES); + ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSCONF), + AC_MSG_RESULT(not usable)) + +dnl check if we have _SC_SIGSTKSZ via sysconf() +AC_MSG_CHECKING(for _SC_SIGSTKSZ via sysconf()) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[#include ], +[ (void)sysconf(_SC_SIGSTKSZ); + ])], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSCONF_SIGSTKSZ), + AC_MSG_RESULT(not usable)) + +AC_CHECK_SIZEOF([int]) +AC_CHECK_SIZEOF([long]) +AC_CHECK_SIZEOF([time_t]) +AC_CHECK_SIZEOF([off_t]) + +dnl Use different names to avoid clashing with other header files. +AC_DEFINE_UNQUOTED(VIM_SIZEOF_INT, [$ac_cv_sizeof_int]) +AC_DEFINE_UNQUOTED(VIM_SIZEOF_LONG, [$ac_cv_sizeof_long]) + +dnl Make sure that uint32_t is really 32 bits unsigned. +AC_MSG_CHECKING([uint32_t is 32 bits]) +AC_RUN_IFELSE([AC_LANG_SOURCE([ +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +int main() { + uint32_t nr1 = (uint32_t)-1; + uint32_t nr2 = (uint32_t)0xffffffffUL; + if (sizeof(uint32_t) != 4 || nr1 != 0xffffffffUL || nr2 + 1 != 0) return 1; + return 0; +}])], +AC_MSG_RESULT(ok), +AC_MSG_ERROR([WRONG! uint32_t not defined correctly.]), +AC_MSG_WARN([cannot check uint32_t when cross-compiling.])) + +dnl Check for memmove() before bcopy(), makes memmove() be used when both are +dnl present, fixes problem with incompatibility between Solaris 2.4 and 2.5. + +[bcopy_test_prog=' +#include "confdefs.h" +#ifdef HAVE_STRING_H +# include +#endif +#if STDC_HEADERS +# include +# include +#endif +int main() { + char buf[10]; + strcpy(buf, "abcdefghi"); + mch_memmove(buf, buf + 2, 3); + if (strncmp(buf, "ababcf", 6)) + exit(1); + strcpy(buf, "abcdefghi"); + mch_memmove(buf + 2, buf, 3); + if (strncmp(buf, "cdedef", 6)) + exit(1); + exit(0); /* libc version works properly. */ +}'] + +AC_CACHE_CHECK([whether memmove handles overlaps],[vim_cv_memmove_handles_overlap], + [ + AC_RUN_IFELSE([AC_LANG_SOURCE([[#define mch_memmove(s,d,l) memmove(d,s,l) $bcopy_test_prog]])], + [ + vim_cv_memmove_handles_overlap=yes + ],[ + vim_cv_memmove_handles_overlap=no + ],[ + AC_MSG_ERROR(cross-compiling: please set 'vim_cv_memmove_handles_overlap') + ]) + ]) + +if test "x$vim_cv_memmove_handles_overlap" = "xyes" ; then + AC_DEFINE(USEMEMMOVE) +else + AC_CACHE_CHECK([whether bcopy handles overlaps],[vim_cv_bcopy_handles_overlap], + [ + AC_RUN_IFELSE([AC_LANG_SOURCE([[#define mch_bcopy(s,d,l) bcopy(d,s,l) $bcopy_test_prog]])], + [ + vim_cv_bcopy_handles_overlap=yes + ],[ + vim_cv_bcopy_handles_overlap=no + ],[ + AC_MSG_ERROR(cross-compiling: please set 'vim_cv_bcopy_handles_overlap') + ]) + ]) + + if test "x$vim_cv_bcopy_handles_overlap" = "xyes" ; then + AC_DEFINE(USEBCOPY) + else + AC_CACHE_CHECK([whether memcpy handles overlaps],[vim_cv_memcpy_handles_overlap], + [ + AC_RUN_IFELSE([AC_LANG_SOURCE([[#define mch_memcpy(s,d,l) memcpy(d,s,l) $bcopy_test_prog]])], + [ + vim_cv_memcpy_handles_overlap=yes + ],[ + vim_cv_memcpy_handles_overlap=no + ],[ + AC_MSG_ERROR(cross-compiling: please set 'vim_cv_memcpy_handles_overlap') + ]) + ]) + + if test "x$vim_cv_memcpy_handles_overlap" = "xyes" ; then + AC_DEFINE(USEMEMCPY) + fi + fi +fi + + +dnl Check for multibyte locale functions +dnl Find out if _Xsetlocale() is supported by libX11. +dnl Check if X_LOCALE should be defined. +if test "x$with_x" = "xyes"; then + cflags_save=$CFLAGS + libs_save=$LIBS + LIBS="$LIBS $X_LIBS $GUI_LIB_LOC $GUI_X_LIBS $X_PRE_LIBS $X_LIB $X_EXTRA_LIBS" + CFLAGS="$CFLAGS $X_CFLAGS" + + AC_MSG_CHECKING(whether X_LOCALE needed) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ],)], + AC_LINK_IFELSE([AC_LANG_CALL([],[_Xsetlocale])], [AC_MSG_RESULT(yes) + AC_DEFINE(X_LOCALE)], AC_MSG_RESULT(no)), + AC_MSG_RESULT(no)) + + AC_MSG_CHECKING(whether Xutf8SetWMProperties() can be used) + AC_LINK_IFELSE([AC_LANG_CALL([],[Xutf8SetWMProperties])], [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_XUTF8SETWMPROPERTIES)], AC_MSG_RESULT(no)) + + CFLAGS=$cflags_save + LIBS=$libs_save +fi + +dnl Link with xpg4, it is said to make Korean locale working +AC_CHECK_LIB(xpg4, _xpg4_setrunelocale, [LIBS="$LIBS -lxpg4"],,) + +dnl Check how we can run ctags. Default to "ctags" when nothing works. +dnl Use --version to detect Exuberant ctags (preferred) +dnl Add --fields=+S to get function signatures for omni completion. +dnl -t for typedefs (many ctags have this) +dnl -s for static functions (Elvis ctags only?) +dnl -v for variables. Dangerous, most ctags take this for 'vgrind style'. +dnl -i+m to test for older Exuberant ctags +AC_MSG_CHECKING(how to create tags) +test -f tags && mv tags tags.save +if (eval ctags --version /dev/null | grep Exuberant) < /dev/null 1>&AS_MESSAGE_LOG_FD 2>&1; then + TAGPRG="ctags -I INIT+,INIT2+,INIT3+,INIT4+,INIT5+ --fields=+S" +elif (eval exctags --version /dev/null | grep Exuberant) < /dev/null 1>&AS_MESSAGE_LOG_FD 2>&1; then + TAGPRG="exctags -I INIT+,INIT2+,INIT3+,INIT4+,INIT5+ --fields=+S" +elif (eval exuberant-ctags --version /dev/null | grep Exuberant) < /dev/null 1>&AS_MESSAGE_LOG_FD 2>&1; then + TAGPRG="exuberant-ctags -I INIT+,INIT2+,INIT3+,INIT4+,INIT5+ --fields=+S" +else + TAGPRG="ctags" + (eval etags /dev/null) < /dev/null 1>&AS_MESSAGE_LOG_FD 2>&1 && TAGPRG="etags" + (eval etags -c /dev/null) < /dev/null 1>&AS_MESSAGE_LOG_FD 2>&1 && TAGPRG="etags -c" + (eval ctags /dev/null) < /dev/null 1>&AS_MESSAGE_LOG_FD 2>&1 && TAGPRG="ctags" + (eval ctags -t /dev/null) < /dev/null 1>&AS_MESSAGE_LOG_FD 2>&1 && TAGPRG="ctags -t" + (eval ctags -ts /dev/null) < /dev/null 1>&AS_MESSAGE_LOG_FD 2>&1 && TAGPRG="ctags -ts" + (eval ctags -tvs /dev/null) < /dev/null 1>&AS_MESSAGE_LOG_FD 2>&1 && TAGPRG="ctags -tvs" + (eval ctags -i+m /dev/null) < /dev/null 1>&AS_MESSAGE_LOG_FD 2>&1 && TAGPRG="ctags -i+m" +fi +test -f tags.save && mv tags.save tags +AC_MSG_RESULT($TAGPRG) AC_SUBST(TAGPRG) + +dnl Check how we can run man with a section number +AC_MSG_CHECKING(how to run man with a section nr) +MANDEF="man" +(eval MANPAGER=cat PAGER=cat man -s 2 read) < /dev/null > /dev/null 2>&AS_MESSAGE_LOG_FD && MANDEF="man -s" +AC_MSG_RESULT($MANDEF) +if test "$MANDEF" = "man -s"; then + AC_DEFINE(USEMAN_S) +fi + +dnl Check if gettext() is working and if it needs -lintl +dnl We take care to base this on an empty LIBS: on some systems libelf would be +dnl in LIBS and implicitly take along libintl. The final LIBS would then not +dnl contain libintl, and the link step would fail due to -Wl,--as-needed. +AC_MSG_CHECKING(--disable-nls argument) +AC_ARG_ENABLE(nls, + [ --disable-nls Don't support NLS (gettext()).], , + [enable_nls="yes"]) + +if test "$enable_nls" = "yes"; then + AC_MSG_RESULT(no) + + INSTALL_LANGS=install-languages + AC_SUBST(INSTALL_LANGS) + INSTALL_TOOL_LANGS=install-tool-languages + AC_SUBST(INSTALL_TOOL_LANGS) + + AC_CHECK_PROG(MSGFMT, msgfmt, msgfmt, ) + AC_MSG_CHECKING([for NLS]) + if test -f po/Makefile; then + have_gettext="no" + if test -n "$MSGFMT"; then + olibs=$LIBS + LIBS="" + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [#include ], + [gettext("Test");])], + AC_MSG_RESULT([gettext() works]); have_gettext="yes"; LIBS=$olibs, + LIBS="-lintl" + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [#include ], + [gettext("Test");])], + AC_MSG_RESULT([gettext() works with -lintl]); have_gettext="yes"; + LIBS="$olibs -lintl", + AC_MSG_RESULT([gettext() doesn't work]); + LIBS=$olibs)) + else + AC_MSG_RESULT([msgfmt not found - disabled]); + fi + if test $have_gettext = "yes" -a "x$features" != "xtiny"; then + AC_DEFINE(HAVE_GETTEXT) + MAKEMO=yes + AC_SUBST(MAKEMO) + dnl this was added in GNU gettext 0.10.36 + AC_CHECK_FUNCS(bind_textdomain_codeset) + dnl _nl_msg_cat_cntr is required for GNU gettext + AC_MSG_CHECKING([for _nl_msg_cat_cntr]) + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [#include + extern int _nl_msg_cat_cntr;], + [++_nl_msg_cat_cntr;])], + AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_NL_MSG_CAT_CNTR), + AC_MSG_RESULT([no])) + AC_MSG_CHECKING([if msgfmt supports --desktop]) + MSGFMT_DESKTOP= + if "$MSGFMT" --help | grep -e '--desktop' >/dev/null; then + if "$MSGFMT" --version | grep '0.19.[[3-7]]$' >/dev/null; then + dnl GNU gettext 0.19.7's --desktop is broken. We assume back to + dnl 0.19.3 is also broken. + AC_MSG_RESULT([broken]) + else + AC_MSG_RESULT([yes]) + MSGFMT_DESKTOP="gvim.desktop vim.desktop" + fi + else + AC_MSG_RESULT([no]) + fi + AC_SUBST(MSGFMT_DESKTOP) + fi + else + AC_MSG_RESULT([no "po/Makefile" - disabled]); + fi +else + AC_MSG_RESULT(yes) +fi + +dnl Check for dynamic linking loader +AC_CHECK_HEADER(dlfcn.h, DLL=dlfcn.h, [AC_CHECK_HEADER(dl.h, DLL=dl.h)]) +if test x${DLL} = xdlfcn.h; then + AC_DEFINE(HAVE_DLFCN_H, 1, [ Define if we have dlfcn.h. ]) + AC_MSG_CHECKING([for dlopen()]) + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ + extern void* dlopen(); + dlopen(); + ])], + AC_MSG_RESULT(yes); + AC_DEFINE(HAVE_DLOPEN, 1, [ Define if we have dlopen() ]), + AC_MSG_RESULT(no); + AC_MSG_CHECKING([for dlopen() in -ldl]) + olibs=$LIBS + LIBS="$LIBS -ldl" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ + extern void* dlopen(); + dlopen(); + ])], + AC_MSG_RESULT(yes); + AC_DEFINE(HAVE_DLOPEN, 1, [ Define if we have dlopen() ]), + AC_MSG_RESULT(no); + LIBS=$olibs)) + dnl ReliantUNIX has dlopen() in libc but everything else in libdl + dnl ick :-) + AC_MSG_CHECKING([for dlsym()]) + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ + extern void* dlsym(); + dlsym(); + ])], + AC_MSG_RESULT(yes); + AC_DEFINE(HAVE_DLSYM, 1, [ Define if we have dlsym() ]), + AC_MSG_RESULT(no); + AC_MSG_CHECKING([for dlsym() in -ldl]) + olibs=$LIBS + LIBS="$LIBS -ldl" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ + extern void* dlsym(); + dlsym(); + ])], + AC_MSG_RESULT(yes); + AC_DEFINE(HAVE_DLSYM, 1, [ Define if we have dlsym() ]), + AC_MSG_RESULT(no); + LIBS=$olibs)) +elif test x${DLL} = xdl.h; then + AC_DEFINE(HAVE_DL_H, 1, [ Define if we have dl.h. ]) + AC_MSG_CHECKING([for shl_load()]) + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ + extern void* shl_load(); + shl_load(); + ])], + AC_MSG_RESULT(yes); + AC_DEFINE(HAVE_SHL_LOAD, 1, [ Define if we have shl_load() ]), + AC_MSG_RESULT(no); + AC_MSG_CHECKING([for shl_load() in -ldld]) + olibs=$LIBS + LIBS="$LIBS -ldld" + AC_LINK_IFELSE([AC_LANG_PROGRAM(,[ + extern void* shl_load(); + shl_load(); + ])], + AC_MSG_RESULT(yes); + AC_DEFINE(HAVE_SHL_LOAD, 1, [ Define if we have shl_load() ]), + AC_MSG_RESULT(no); + LIBS=$olibs)) +fi +AC_CHECK_HEADERS(setjmp.h) + +if test "x$MACOS_X" = "xyes" -a -n "$PERL"; then + dnl -ldl must come after DynaLoader.a + if echo $LIBS | grep -e '-ldl' >/dev/null; then + LIBS=`echo $LIBS | sed s/-ldl//` + PERL_LIBS="$PERL_LIBS -ldl" + fi +fi + +if test "$MACOS_X" = "yes"; then + AC_MSG_CHECKING([whether we need macOS frameworks]) + if test "$MACOS_X_DARWIN" = "yes"; then + if test "$features" = "tiny"; then + dnl Since no FEAT_CLIPBOARD or FEAT_SOUND, no need for os_macosx.m. + OS_EXTRA_SRC=`echo "$OS_EXTRA_SRC" | sed -e 's+os_macosx.m++'` + OS_EXTRA_OBJ=`echo "$OS_EXTRA_OBJ" | sed -e 's+objects/os_macosx.o++'` + AC_MSG_RESULT([yes, we need CoreServices]) + LIBS="$LIBS -framework CoreServices" + else + AC_MSG_RESULT([yes, we need AppKit]) + LIBS="$LIBS -framework AppKit" + fi + else + AC_MSG_RESULT([no]) + fi +fi + +dnl On some systems REENTRANT needs to be defined. It should not hurt to use +dnl it everywhere. +if `echo "$CFLAGS" | grep -v D_REENTRANT >/dev/null`; then + CFLAGS="$CFLAGS -D_REENTRANT" +fi + +dnl gcc 3.1 changed the meaning of -MM. The only solution appears to be to +dnl use "-isystem" instead of "-I" for all non-Vim include dirs. +dnl But only when making dependencies, cproto and lint don't take "-isystem". +dnl Mac gcc returns "powerpc-apple-darwin8-gcc-4.0.1 (GCC)...", need to allow +dnl the number before the version number. +DEPEND_CFLAGS_FILTER= +if test "$GCC" = yes; then + AC_MSG_CHECKING(for GCC 3 or later) + gccmajor=`echo "$gccversion" | sed -e 's/^\([[1-9]][[0-9]]*\)\..*$/\1/g'` + if test "$gccmajor" -gt "2"; then + DEPEND_CFLAGS_FILTER="| sed 's+-I */+-isystem /+g'" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + dnl -D_FORTIFY_SOURCE=2 crashes Vim on strcpy(buf, "000") when buf is + dnl declared as char x[1] but actually longer. Introduced in gcc 4.0. + dnl Also remove duplicate _FORTIFY_SOURCE arguments. + dnl And undefine it first to avoid a warning. + AC_MSG_CHECKING(whether we need -D_FORTIFY_SOURCE=1) + if test "$gccmajor" -gt "3"; then + CFLAGS=`echo "$CFLAGS" | sed -e 's/-D_FORTIFY_SOURCE=.,//g' -e 's/ *-Wp,-D_FORTIFY_SOURCE=. / /g' -e 's/,-D_FORTIFY_SOURCE=. //g' -e 's/ *-D_FORTIFY_SOURCE=.//g' -e 's/ *-Wp,-U_FORTIFY_SOURCE/ /g' -e 's/ *-U_FORTIFY_SOURCE//g' -e 's/$/ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1/'` + CPPFLAGS=`echo "$CPPFLAGS" | sed -e 's/-D_FORTIFY_SOURCE=.,//g' -e 's/ *-Wp,-D_FORTIFY_SOURCE=. / /g' -e 's/,-D_FORTIFY_SOURCE=. //g' -e 's/ *-D_FORTIFY_SOURCE=.//g' -e 's/ *-Wp,-U_FORTIFY_SOURCE/ /g' -e 's/ *-U_FORTIFY_SOURCE//g'` + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi +fi +AC_SUBST(DEPEND_CFLAGS_FILTER) + +dnl On some systems AC_SYS_LARGEFILE determines that -D_FILE_OFFSET_BITS=64 +dnl isn't required, but the CFLAGS for some of the libraries we're using +dnl include the define. Since the define changes the size of some datatypes +dnl (e.g. ino_t and off_t), all of Vim's modules must be compiled with a +dnl consistent value. It's therefore safest to force the use of the define +dnl if it's present in any of the *_CFLAGS variables. +AC_MSG_CHECKING(whether we need to force -D_FILE_OFFSET_BITS=64) +if echo "$CFLAGS $LUA_CFLAGS $MZSCHEME_CFLAGS $PERL_CFLAGS $PYTHON_CFLAGS $PYTHON3_CFLAGS $TCL_CFLAGS $RUBY_CFLAGS $GTK_CFLAGS" | grep -q D_FILE_OFFSET_BITS 2>/dev/null; then + AC_MSG_RESULT(yes) + AC_DEFINE(_FILE_OFFSET_BITS, 64) +else + AC_MSG_RESULT(no) +fi + +dnl $LDFLAGS is passed to glibtool in libvterm, it doesn't like a space +dnl between "-L" and the path that follows. +LDFLAGS=`echo "$LDFLAGS" | sed -e 's/-L /-L/g'` + +dnl link.sh tries to avoid overlinking in a hackish way. +dnl At least GNU ld supports --as-needed which provides the same functionality +dnl at linker level. Let's use it. +AC_MSG_CHECKING(linker --as-needed support) +LINK_AS_NEEDED= +# Check if linker supports --as-needed and --no-as-needed options +if $CC -Wl,--help 2>/dev/null | grep as-needed > /dev/null; then + if ! echo "$LDFLAGS" | grep -q -- '-Wl,[[^[:space:]]]*--as-needed'; then + LDFLAGS="$LDFLAGS -Wl,--as-needed" + fi + LINK_AS_NEEDED=yes +fi +if test "$LINK_AS_NEEDED" = yes; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_SUBST(LINK_AS_NEEDED) + +# IBM z/OS reset CFLAGS for config.mk +if test "$zOSUnix" = "yes"; then + CFLAGS="-D_ALL_SOURCE -Wc,float\(ieee\),dll" +fi + +dnl write output files +AC_CONFIG_FILES(auto/config.mk:config.mk.in) +AC_OUTPUT + +dnl vim: set sw=2 tw=78 fo+=l: diff --git a/src/create_cmdidxs.vim b/src/create_cmdidxs.vim new file mode 100644 index 0000000..2f8ad1f --- /dev/null +++ b/src/create_cmdidxs.vim @@ -0,0 +1,104 @@ +" This script generates the tables cmdidxs1[] and cmdidxs2[][] which, +" given a Ex command, determine the first value to probe to find +" a matching command in cmdnames[] based on the first character +" and the first 2 characters of the command. +" This is used to speed up lookup in cmdnames[]. +" +" Script should be run every time new Ex commands are added in Vim, +" from the src/vim directory, since it reads commands from "ex_cmds.h". + +let cmds = [] +let skipped_cmds = 0 + +let lines = readfile('ex_cmds.h') +let idx = 0 +while idx < len(lines) + let line = lines[idx] + if line =~ '^EXCMD(CMD_' + let m = matchlist(line, '^EXCMD(CMD_\S*,\s*"\([a-z][^"]*\)"') + if len(m) >= 2 + let cmds += [ m[1] ] + else + let skipped_cmds += 1 + endif + + let idx += 1 + let flags = lines[idx] + let idx += 1 + let addr_type = lines[idx] + + if flags =~ '\' + if addr_type =~ 'ADDR_NONE' + echoerr 'ex_cmds.h:' .. (idx - 1) .. ': Using EX_RANGE with ADDR_NONE: ' .. line + endif + else + if addr_type !~ 'ADDR_NONE' + echoerr 'ex_cmds.h:' .. (idx - 1) .. ': Missing ADDR_NONE: ' .. line + endif + endif + + if flags =~ '\' && (addr_type =~ 'ADDR_OTHER' || addr_type =~ 'ADDR_NONE') + echoerr 'ex_cmds.h:' .. (idx - 1) .. ': Missing misplaced EX_DFLALL: ' .. line + endif + endif + let idx += 1 +endwhile + +let cmdidxs1 = {} +let cmdidxs2 = {} + +for i in range(len(cmds) - 1, 0, -1) + let cmd = cmds[i] + let c1 = cmd[0] " First character of command + let c2 = cmd[1] " Second character of command (if any) + + let cmdidxs1{c1} = i + if c2 >= 'a' && c2 <= 'z' + let cmdidxs2{c1}{c2} = i + endif +endfor + +let output = [ '/* Automatically generated code by create_cmdidxs.vim' ] +let output += [ ' *' ] +let output += [ ' * Table giving the index of the first command in cmdnames[] to lookup' ] +let output += [ ' * based on the first letter of a command.' ] +let output += [ ' */' ] +let output += [ 'static const unsigned short cmdidxs1[26] =' ] +let output += [ '{' ] + +let a_to_z = map(range(char2nr('a'), char2nr('z')), 'nr2char(v:val)') +for c1 in a_to_z + let line = ' /* ' . c1 . ' */ ' . cmdidxs1{c1} . ((c1 == 'z') ? '' : ',') + let output += [ line ] +endfor +let output += [ '};' ] +let output += [ '' ] +let output += [ '/*' ] +let output += [ ' * Table giving the index of the first command in cmdnames[] to lookup' ] +let output += [ ' * based on the first 2 letters of a command.' ] +let output += [ ' * Values in cmdidxs2[c1][c2] are relative to cmdidxs1[c1] so that they' ] +let output += [ ' * fit in a byte.' ] +let output += [ ' */' ] +let output += [ 'static const unsigned char cmdidxs2[26][26] =' ] +let output += [ '{ /* a b c d e f g h i j k l m n o p q r s t u v w x y z */' ] + +for c1 in a_to_z + let line = ' /* ' . c1 . ' */ {' + for c2 in a_to_z + if exists('cmdidxs2{c1}{c2}') + let line .= printf('%3d', cmdidxs2{c1}{c2} - cmdidxs1{c1}) + else + let line .= ' 0' + endif + let line .= (c2 == 'z') ? '' : ',' + endfor + let line .= ' }' . ((c1 == 'z') ? '' : ',') + let output += [ line ] +endfor + +let output += [ '};' ] +let output += [ '' ] +let output += [ 'static const int command_count = ' . (len(cmds) + skipped_cmds) . ';' ] + +call writefile(output, "ex_cmdidxs.h") +quit diff --git a/src/create_nvcmdidxs.c b/src/create_nvcmdidxs.c new file mode 100644 index 0000000..1d084f5 --- /dev/null +++ b/src/create_nvcmdidxs.c @@ -0,0 +1,38 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar et al. + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * create_nvcmdidxs.c: helper program for `make nvcmdidxs` + * + * This outputs the list of command characters from the nv_cmds table in + * decimal form, one per line. + */ + +#include "vim.h" + +// Declare nv_cmds[]. +#include "nv_cmds.h" + +#include + +int main(void) +{ + size_t i; + + for (i = 0; i < NV_CMDS_SIZE; i++) + { + int cmdchar = nv_cmds[i]; + + // Special keys are negative, use the negated value for sorting. + if (cmdchar < 0) + cmdchar = -cmdchar; + printf("%d\n", cmdchar); + } + return 0; +} diff --git a/src/create_nvcmdidxs.vim b/src/create_nvcmdidxs.vim new file mode 100644 index 0000000..1319276 --- /dev/null +++ b/src/create_nvcmdidxs.vim @@ -0,0 +1,60 @@ +" This script generates the table nv_cmd_idx[] which contains the index in +" nv_cmds[] table (normal.c) for each of the command character supported in +" normal/visual mode. +" This is used to speed up the command lookup in nv_cmds[]. +" +" Script should be run using "make nvcmdidxs", every time the nv_cmds[] table +" in src/nv_cmds.h changes. +" +" This is written in legacy Vim script so that it can be run by a slightly +" older Vim version. + +" Generate the table of normal/visual mode command characters and their +" corresponding index. +let cmd = 'create_nvcmdidxs' +if has('unix') + let cmd = './' .. cmd +endif +let nv_cmdtbl = systemlist(cmd)->map({i, ch -> {'idx': i, 'cmdchar': ch}}) + +" sort the table by the command character +call sort(nv_cmdtbl, {a, b -> a.cmdchar - b.cmdchar}) + +" Compute the highest index upto which the command character can be directly +" used as an index. +let nv_max_linear = 0 +for i in range(nv_cmdtbl->len()) + if i != nv_cmdtbl[i].cmdchar + let nv_max_linear = i - 1 + break + endif +endfor + +" Generate a header file with the table +let output =<< trim END + /* + * Automatically generated code by the create_nvcmdidxs.vim script. + * + * Table giving the index in nv_cmds[] to lookup based on + * the command character. + */ + + // nv_cmd_idx[] => nv_cmds[] index + static const unsigned short nv_cmd_idx[] = + { +END + +" Add each command character in comment and the corresponding index +let output += nv_cmdtbl->map({_, v -> + \ printf(' /* %5d */ %3d,', v.cmdchar, v.idx)}) + +let output += ['};', '', + \ '// The highest index for which', + \ '// nv_cmds[idx].cmd_char == nv_cmd_idx[nv_cmds[idx].cmd_char]'] + +let output += ['static const int nv_max_linear = ' .. nv_max_linear .. ';'] + +call writefile(output, "nv_cmdidxs.h") +quit + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/crypt.c b/src/crypt.c new file mode 100644 index 0000000..b4b48c8 --- /dev/null +++ b/src/crypt.c @@ -0,0 +1,1163 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * crypt.c: Generic encryption support. + */ +#include "vim.h" + +#if defined(FEAT_CRYPT) || defined(PROTO) +/* + * Optional encryption support. + * Mohsin Ahmed, mosh@sasi.com, 1998-09-24 + * Based on zip/crypt sources. + * Refactored by David Leadbeater, 2014. + * + * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to + * most countries. There are a few exceptions, but that still should not be a + * problem since this code was originally created in Europe and India. + * + * Blowfish addition originally made by Mohsin Ahmed, + * http://www.cs.albany.edu/~mosh 2010-03-14 + * Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html) + * and sha256 by Christophe Devine. + */ + +typedef struct { + char *name; // encryption name as used in 'cryptmethod' + char *magic; // magic bytes stored in file header + int salt_len; // length of salt, or 0 when not using salt + int seed_len; // length of seed, or 0 when not using seed +#ifdef CRYPT_NOT_INPLACE + int works_inplace; // encryption/decryption can be done in-place +#endif + int whole_undofile; // whole undo file is encrypted + + // Optional function pointer for a self-test. + int (* self_test_fn)(); + + // Function pointer for initializing encryption/decryption. + int (* init_fn)(cryptstate_T *state, char_u *key, + char_u *salt, int salt_len, char_u *seed, int seed_len); + + // Function pointers for encoding/decoding from one buffer into another. + // Optional, however, these or the _buffer ones should be configured. + void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len, + char_u *to, int last); + void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len, + char_u *to, int last); + + // Function pointers for encoding and decoding, can buffer data if needed. + // Optional (however, these or the above should be configured). + long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len, + char_u **newptr, int last); + long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len, + char_u **newptr, int last); + + // Function pointers for in-place encoding and decoding, used for + // crypt_*_inplace(). "from" and "to" arguments will be equal. + // These may be the same as decode_fn and encode_fn above, however an + // algorithm may implement them in a way that is not interchangeable with + // the crypt_(en|de)code() interface (for example because it wishes to add + // padding to files). + // This method is used for swap and undo files which have a rigid format. + void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len, + char_u *p2, int last); + void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len, + char_u *p2, int last); +} cryptmethod_T; + +static int crypt_sodium_init_(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len); +static long crypt_sodium_buffer_decode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last); +static long crypt_sodium_buffer_encode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last); + +// index is method_nr of cryptstate_T, CRYPT_M_* +static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = { + // PK_Zip; very weak + { + "zip", + "VimCrypt~01!", + 0, + 0, +#ifdef CRYPT_NOT_INPLACE + TRUE, +#endif + FALSE, + NULL, + crypt_zip_init, + crypt_zip_encode, crypt_zip_decode, + NULL, NULL, + crypt_zip_encode, crypt_zip_decode, + }, + + // Blowfish/CFB + SHA-256 custom key derivation; implementation issues. + { + "blowfish", + "VimCrypt~02!", + 8, + 8, +#ifdef CRYPT_NOT_INPLACE + TRUE, +#endif + FALSE, + blowfish_self_test, + crypt_blowfish_init, + crypt_blowfish_encode, crypt_blowfish_decode, + NULL, NULL, + crypt_blowfish_encode, crypt_blowfish_decode, + }, + + // Blowfish/CFB + SHA-256 custom key derivation; fixed. + { + "blowfish2", + "VimCrypt~03!", + 8, + 8, +#ifdef CRYPT_NOT_INPLACE + TRUE, +#endif + TRUE, + blowfish_self_test, + crypt_blowfish_init, + crypt_blowfish_encode, crypt_blowfish_decode, + NULL, NULL, + crypt_blowfish_encode, crypt_blowfish_decode, + }, + + // XChaCha20 using libsodium + { + "xchacha20", + "VimCrypt~04!", +#ifdef FEAT_SODIUM + crypto_pwhash_argon2id_SALTBYTES, // 16 +#else + 16, +#endif + 8, +#ifdef CRYPT_NOT_INPLACE + FALSE, +#endif + FALSE, + NULL, + crypt_sodium_init_, + NULL, NULL, + crypt_sodium_buffer_encode, crypt_sodium_buffer_decode, + NULL, NULL, + }, + + // NOTE: when adding a new method, use some random bytes for the magic key, + // to avoid that a text file is recognized as encrypted. +}; + +#if defined(FEAT_SODIUM) || defined(PROTO) +typedef struct { + size_t count; + unsigned char key[crypto_box_SEEDBYTES]; + // 32, same as crypto_secretstream_xchacha20poly1305_KEYBYTES + crypto_secretstream_xchacha20poly1305_state + state; +} sodium_state_T; + + +# ifdef DYNAMIC_SODIUM +# ifdef MSWIN +# define SODIUM_PROC FARPROC +# define load_dll vimLoadLib +# define symbol_from_dll GetProcAddress +# define close_dll FreeLibrary +# define load_dll_error GetWin32Error +# else +# error Dynamic loading of libsodium is not supported for now. +//# define HINSTANCE void* +//# define SODIUM_PROC void* +//# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL) +//# define symbol_from_dll dlsym +//# define close_dll dlclose +//# define load_dll_error dlerror +# endif + +# define sodium_init load_sodium +# define sodium_free dll_sodium_free +# define sodium_malloc dll_sodium_malloc +# define sodium_memzero dll_sodium_memzero +# define sodium_mlock dll_sodium_mlock +# define sodium_munlock dll_sodium_munlock +# define crypto_secretstream_xchacha20poly1305_init_push \ + dll_crypto_secretstream_xchacha20poly1305_init_push +# define crypto_secretstream_xchacha20poly1305_push \ + dll_crypto_secretstream_xchacha20poly1305_push +# define crypto_secretstream_xchacha20poly1305_init_pull \ + dll_crypto_secretstream_xchacha20poly1305_init_pull +# define crypto_secretstream_xchacha20poly1305_pull \ + dll_crypto_secretstream_xchacha20poly1305_pull +# define crypto_pwhash dll_crypto_pwhash +# define randombytes_buf dll_randombytes_buf +# define randombytes_random dll_randombytes_random + +static int (*dll_sodium_init)(void) = NULL; +static void (*dll_sodium_free)(void *) = NULL; +static void *(*dll_sodium_malloc)(const size_t) = NULL; +static void (*dll_sodium_memzero)(void * const, const size_t) = NULL; +static int (*dll_sodium_mlock)(void * const, const size_t) = NULL; +static int (*dll_sodium_munlock)(void * const, const size_t) = NULL; +static int (*dll_crypto_secretstream_xchacha20poly1305_init_push) + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char [], + const unsigned char []) = NULL; +static int (*dll_crypto_secretstream_xchacha20poly1305_push) + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *c, unsigned long long *clen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, unsigned char tag) + = NULL; +static int (*dll_crypto_secretstream_xchacha20poly1305_init_pull) + (crypto_secretstream_xchacha20poly1305_state *state, + const unsigned char [], + const unsigned char []) = NULL; +static int (*dll_crypto_secretstream_xchacha20poly1305_pull) + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen) = NULL; +static int (*dll_crypto_pwhash)(unsigned char * const out, + unsigned long long outlen, + const char * const passwd, unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, size_t memlimit, int alg) + = NULL; +static void (*dll_randombytes_buf)(void * const buf, const size_t size); +static uint32_t (*dll_randombytes_random)(void); + +static struct { + const char *name; + SODIUM_PROC *ptr; +} sodium_funcname_table[] = { + {"sodium_init", (SODIUM_PROC*)&dll_sodium_init}, + {"sodium_free", (SODIUM_PROC*)&dll_sodium_free}, + {"sodium_malloc", (SODIUM_PROC*)&dll_sodium_malloc}, + {"sodium_memzero", (SODIUM_PROC*)&dll_sodium_memzero}, + {"sodium_mlock", (SODIUM_PROC*)&dll_sodium_mlock}, + {"sodium_munlock", (SODIUM_PROC*)&dll_sodium_munlock}, + {"crypto_secretstream_xchacha20poly1305_init_push", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_init_push}, + {"crypto_secretstream_xchacha20poly1305_push", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_push}, + {"crypto_secretstream_xchacha20poly1305_init_pull", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_init_pull}, + {"crypto_secretstream_xchacha20poly1305_pull", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_pull}, + {"crypto_pwhash", (SODIUM_PROC*)&dll_crypto_pwhash}, + {"randombytes_buf", (SODIUM_PROC*)&dll_randombytes_buf}, + {"randombytes_random", (SODIUM_PROC*)&dll_randombytes_random}, + {NULL, NULL} +}; + + static int +sodium_runtime_link_init(int verbose) +{ + static HINSTANCE hsodium = NULL; + const char *libname = DYNAMIC_SODIUM_DLL; + int i; + + if (hsodium != NULL) + return OK; + + hsodium = load_dll(libname); + if (hsodium == NULL) + { + if (verbose) + semsg(_(e_could_not_load_library_str_str), libname, load_dll_error()); + return FAIL; + } + + for (i = 0; sodium_funcname_table[i].ptr; ++i) + { + if ((*sodium_funcname_table[i].ptr = symbol_from_dll(hsodium, + sodium_funcname_table[i].name)) == NULL) + { + close_dll(hsodium); + hsodium = NULL; + if (verbose) + semsg(_(e_could_not_load_library_function_str), sodium_funcname_table[i].name); + return FAIL; + } + } + return OK; +} + + static int +load_sodium(void) +{ + if (sodium_runtime_link_init(TRUE) == FAIL) + return -1; + return dll_sodium_init(); +} +# endif + +# if defined(DYNAMIC_SODIUM) || defined(PROTO) + int +sodium_enabled(int verbose) +{ + return sodium_runtime_link_init(verbose) == OK; +} +# endif +#endif + +#define CRYPT_MAGIC_LEN 12 // cannot change +static char crypt_magic_head[] = "VimCrypt~"; + +/* + * Return int value for crypt method name. + * 0 for "zip", the old method. Also for any non-valid value. + * 1 for "blowfish". + * 2 for "blowfish2". + */ + int +crypt_method_nr_from_name(char_u *name) +{ + int i; + + for (i = 0; i < CRYPT_M_COUNT; ++i) + if (STRCMP(name, cryptmethods[i].name) == 0) + return i; + return 0; +} + +/* + * Get the crypt method used for a file from "ptr[len]", the magic text at the + * start of the file. + * Returns -1 when no encryption used. + */ + int +crypt_method_nr_from_magic(char *ptr, int len) +{ + int i; + + if (len < CRYPT_MAGIC_LEN) + return -1; + + for (i = 0; i < CRYPT_M_COUNT; i++) + if (memcmp(ptr, cryptmethods[i].magic, CRYPT_MAGIC_LEN) == 0) + return i; + + i = (int)STRLEN(crypt_magic_head); + if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0) + emsg(_(e_file_is_encrypted_with_unknown_method)); + + return -1; +} + +#ifdef CRYPT_NOT_INPLACE +/* + * Return TRUE if the crypt method for "method_nr" can be done in-place. + */ + int +crypt_works_inplace(cryptstate_T *state) +{ + return cryptmethods[state->method_nr].works_inplace; +} +#endif + +/* + * Get the crypt method for buffer "buf" as a number. + */ + int +crypt_get_method_nr(buf_T *buf) +{ + return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm); +} + +/* + * Return TRUE when the buffer uses an encryption method that encrypts the + * whole undo file, not only the text. + */ + int +crypt_whole_undofile(int method_nr) +{ + return cryptmethods[method_nr].whole_undofile; +} + +/* + * Get crypt method specific length of the file header in bytes. + */ + int +crypt_get_header_len(int method_nr) +{ + return CRYPT_MAGIC_LEN + + cryptmethods[method_nr].salt_len + + cryptmethods[method_nr].seed_len; +} + + +#if defined(FEAT_SODIUM) || defined(PROTO) +/* + * Get maximum crypt method specific length of the file header in bytes. + */ + int +crypt_get_max_header_len(void) +{ + int i; + int max = 0; + int temp = 0; + + for (i = 0; i < CRYPT_M_COUNT; ++i) + { + temp = crypt_get_header_len(i); + if (temp > max) + max = temp; + } + return max; +} +#endif + +/* + * Set the crypt method for buffer "buf" to "method_nr" using the int value as + * returned by crypt_method_nr_from_name(). + */ + void +crypt_set_cm_option(buf_T *buf, int method_nr) +{ + free_string_option(buf->b_p_cm); + buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name); +} + +/* + * If the crypt method for the current buffer has a self-test, run it and + * return OK/FAIL. + */ + int +crypt_self_test(void) +{ + int method_nr = crypt_get_method_nr(curbuf); + + if (cryptmethods[method_nr].self_test_fn == NULL) + return OK; + return cryptmethods[method_nr].self_test_fn(); +} + +/* + * Allocate a crypt state and initialize it. + * Return NULL for failure. + */ + cryptstate_T * +crypt_create( + int method_nr, + char_u *key, + char_u *salt, + int salt_len, + char_u *seed, + int seed_len) +{ + cryptstate_T *state = ALLOC_ONE(cryptstate_T); + + if (state == NULL) + return state; + + state->method_nr = method_nr; + if (cryptmethods[method_nr].init_fn( + state, key, salt, salt_len, seed, seed_len) == FAIL) + { + vim_free(state); + return NULL; + } + return state; +} + +/* + * Allocate a crypt state from a file header and initialize it. + * Assumes that header contains at least the number of bytes that + * crypt_get_header_len() returns for "method_nr". + */ + cryptstate_T * +crypt_create_from_header( + int method_nr, + char_u *key, + char_u *header) +{ + char_u *salt = NULL; + char_u *seed = NULL; + int salt_len = cryptmethods[method_nr].salt_len; + int seed_len = cryptmethods[method_nr].seed_len; + + if (salt_len > 0) + salt = header + CRYPT_MAGIC_LEN; + if (seed_len > 0) + seed = header + CRYPT_MAGIC_LEN + salt_len; + + return crypt_create(method_nr, key, salt, salt_len, seed, seed_len); +} + +/* + * Read the crypt method specific header data from "fp". + * Return an allocated cryptstate_T or NULL on error. + */ + cryptstate_T * +crypt_create_from_file(FILE *fp, char_u *key) +{ + int method_nr; + int header_len; + char magic_buffer[CRYPT_MAGIC_LEN]; + char_u *buffer; + cryptstate_T *state; + + if (fread(magic_buffer, CRYPT_MAGIC_LEN, 1, fp) != 1) + return NULL; + method_nr = crypt_method_nr_from_magic(magic_buffer, CRYPT_MAGIC_LEN); + if (method_nr < 0) + return NULL; + + header_len = crypt_get_header_len(method_nr); + if ((buffer = alloc(header_len)) == NULL) + return NULL; + mch_memmove(buffer, magic_buffer, CRYPT_MAGIC_LEN); + if (header_len > CRYPT_MAGIC_LEN + && fread(buffer + CRYPT_MAGIC_LEN, + header_len - CRYPT_MAGIC_LEN, 1, fp) != 1) + { + vim_free(buffer); + return NULL; + } + + state = crypt_create_from_header(method_nr, key, buffer); + vim_free(buffer); + return state; +} + +/* + * Allocate a cryptstate_T for writing and initialize it with "key". + * Allocates and fills in the header and stores it in "header", setting + * "header_len". The header may include salt and seed, depending on + * cryptmethod. Caller must free header. + * Returns the state or NULL on failure. + */ + cryptstate_T * +crypt_create_for_writing( + int method_nr, + char_u *key, + char_u **header, + int *header_len) +{ + int len = crypt_get_header_len(method_nr); + char_u *salt = NULL; + char_u *seed = NULL; + int salt_len = cryptmethods[method_nr].salt_len; + int seed_len = cryptmethods[method_nr].seed_len; + cryptstate_T *state; + + *header_len = len; + *header = alloc(len); + if (*header == NULL) + return NULL; + + mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN); + if (salt_len > 0 || seed_len > 0) + { + if (salt_len > 0) + salt = *header + CRYPT_MAGIC_LEN; + if (seed_len > 0) + seed = *header + CRYPT_MAGIC_LEN + salt_len; + + // TODO: Should this be crypt method specific? (Probably not worth + // it). sha2_seed is pretty bad for large amounts of entropy, so make + // that into something which is suitable for anything. +#ifdef FEAT_SODIUM + if (sodium_init() >= 0) + { + if (salt_len > 0) + randombytes_buf(salt, salt_len); + if (seed_len > 0) + randombytes_buf(seed, seed_len); + } + else +#endif + sha2_seed(salt, salt_len, seed, seed_len); + } + state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len); + if (state == NULL) + VIM_CLEAR(*header); + return state; +} + +/* + * Free the crypt state. + */ + void +crypt_free_state(cryptstate_T *state) +{ +#ifdef FEAT_SODIUM + if (state->method_nr == CRYPT_M_SOD) + { + sodium_munlock(((sodium_state_T *)state->method_state)->key, + crypto_box_SEEDBYTES); + sodium_memzero(state->method_state, sizeof(sodium_state_T)); + sodium_free(state->method_state); + } + else +#endif + vim_free(state->method_state); + vim_free(state); +} + +#ifdef CRYPT_NOT_INPLACE +/* + * Encode "from[len]" and store the result in a newly allocated buffer, which + * is stored in "newptr". + * Return number of bytes in "newptr", 0 for need more or -1 on error. + */ + long +crypt_encode_alloc( + cryptstate_T *state, + char_u *from, + size_t len, + char_u **newptr, + int last) +{ + cryptmethod_T *method = &cryptmethods[state->method_nr]; + + if (method->encode_buffer_fn != NULL) + // Has buffer function, pass through. + return method->encode_buffer_fn(state, from, len, newptr, last); + if (len == 0) + // Not buffering, just return EOF. + return (long)len; + + *newptr = alloc(len + 50); + if (*newptr == NULL) + return -1; + method->encode_fn(state, from, len, *newptr, last); + return (long)len; +} + +/* + * Decrypt "ptr[len]" and store the result in a newly allocated buffer, which + * is stored in "newptr". + * Return number of bytes in "newptr", 0 for need more or -1 on error. + */ + long +crypt_decode_alloc( + cryptstate_T *state, + char_u *ptr, + long len, + char_u **newptr, + int last) +{ + cryptmethod_T *method = &cryptmethods[state->method_nr]; + + if (method->decode_buffer_fn != NULL) + // Has buffer function, pass through. + return method->decode_buffer_fn(state, ptr, len, newptr, last); + + if (len == 0) + // Not buffering, just return EOF. + return len; + + *newptr = alloc(len); + if (*newptr == NULL) + return -1; + method->decode_fn(state, ptr, len, *newptr, last); + return len; +} +#endif + +/* + * Encrypting "from[len]" into "to[len]". + */ + void +crypt_encode( + cryptstate_T *state, + char_u *from, + size_t len, + char_u *to, + int last) +{ + cryptmethods[state->method_nr].encode_fn(state, from, len, to, last); +} + +#if 0 // unused +/* + * decrypting "from[len]" into "to[len]". + */ + void +crypt_decode( + cryptstate_T *state, + char_u *from, + size_t len, + char_u *to, + int last) +{ + cryptmethods[state->method_nr].decode_fn(state, from, len, to, last); +} +#endif + +/* + * Simple inplace encryption, modifies "buf[len]" in place. + */ + void +crypt_encode_inplace( + cryptstate_T *state, + char_u *buf, + size_t len, + int last) +{ + cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len, + buf, last); +} + +/* + * Simple inplace decryption, modifies "buf[len]" in place. + */ + void +crypt_decode_inplace( + cryptstate_T *state, + char_u *buf, + size_t len, + int last) +{ + cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len, + buf, last); +} + +/* + * Free an allocated crypt key. Clear the text to make sure it doesn't stay + * in memory anywhere. + */ + void +crypt_free_key(char_u *key) +{ + char_u *p; + + if (key != NULL) + { + for (p = key; *p != NUL; ++p) + *p = 0; + vim_free(key); + } +} + +/* + * Check the crypt method and give a warning if it's outdated. + */ + void +crypt_check_method(int method) +{ + if (method < CRYPT_M_BF2) + { + msg_scroll = TRUE; + msg(_("Warning: Using a weak encryption method; see :help 'cm'")); + } +} + +#ifdef FEAT_SODIUM + static void +crypt_check_swapfile_curbuf(void) +{ + int method = crypt_get_method_nr(curbuf); + if (method == CRYPT_M_SOD) + { + // encryption uses padding and MAC, that does not work very well with + // swap and undo files, so disable them + mf_close_file(curbuf, TRUE); // remove the swap file + set_option_value_give_err((char_u *)"swf", 0, NULL, OPT_LOCAL); + msg_scroll = TRUE; + msg(_("Note: Encryption of swapfile not supported, disabling swap file")); + } +} +#endif + + void +crypt_check_current_method(void) +{ + crypt_check_method(crypt_get_method_nr(curbuf)); +} + +/* + * Ask the user for a crypt key. + * When "store" is TRUE, the new key is stored in the 'key' option, and the + * 'key' option value is returned: Don't free it. + * When "store" is FALSE, the typed key is returned in allocated memory. + * Returns NULL on failure. + */ + char_u * +crypt_get_key( + int store, + int twice) // Ask for the key twice. +{ + char_u *p1, *p2 = NULL; + int round; + + for (round = 0; ; ++round) + { + cmdline_star = TRUE; + cmdline_row = msg_row; + p1 = getcmdline_prompt(NUL, round == 0 + ? (char_u *)_("Enter encryption key: ") + : (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING, + NULL); + cmdline_star = FALSE; + + if (p1 == NULL) + break; + + if (round == twice) + { + if (p2 != NULL && STRCMP(p1, p2) != 0) + { + msg(_("Keys don't match!")); + crypt_free_key(p1); + crypt_free_key(p2); + p2 = NULL; + round = -1; // do it again + continue; + } + + if (store) + { + set_option_value_give_err((char_u *)"key", 0L, p1, OPT_LOCAL); + crypt_free_key(p1); + p1 = curbuf->b_p_key; +#ifdef FEAT_SODIUM + crypt_check_swapfile_curbuf(); +#endif + } + break; + } + p2 = p1; + } + + // since the user typed this, no need to wait for return + if (crypt_get_method_nr(curbuf) != CRYPT_M_SOD) + { + if (msg_didout) + msg_putchar('\n'); + need_wait_return = FALSE; + msg_didout = FALSE; + } + + crypt_free_key(p2); + return p1; +} + + +/* + * Append a message to IObuff for the encryption/decryption method being used. + */ + void +crypt_append_msg( + buf_T *buf) +{ + if (crypt_get_method_nr(buf) == 0) + STRCAT(IObuff, _("[crypted]")); + else + { + STRCAT(IObuff, "["); + STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm); + STRCAT(IObuff, "]"); + } +} + + static int +crypt_sodium_init_( + cryptstate_T *state UNUSED, + char_u *key UNUSED, + char_u *salt UNUSED, + int salt_len UNUSED, + char_u *seed UNUSED, + int seed_len UNUSED) +{ +# ifdef FEAT_SODIUM + // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES + unsigned char dkey[crypto_box_SEEDBYTES]; // 32 + sodium_state_T *sd_state; + int retval = 0; + + if (sodium_init() < 0) + return FAIL; + + sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T)); + sodium_memzero(sd_state, sizeof(sodium_state_T)); + + // derive a key from the password + if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key), salt, + crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE, + crypto_pwhash_ALG_DEFAULT) != 0) + { + // out of memory + sodium_free(sd_state); + return FAIL; + } + memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES); + + retval += sodium_mlock(sd_state->key, crypto_box_SEEDBYTES); + retval += sodium_mlock(key, STRLEN(key)); + + if (retval < 0) + { + emsg(_(e_encryption_sodium_mlock_failed)); + sodium_free(sd_state); + return FAIL; + } + sd_state->count = 0; + state->method_state = sd_state; + + return OK; +# else + emsg(e_libsodium_not_built_in); + return FAIL; +# endif +} + +/* + * Encrypt "from[len]" into "to[len]". + * "from" and "to" can be equal to encrypt in place. + * Call needs to ensure that there is enough space in to (for the header) + */ +#if 0 // Currently unused + void +crypt_sodium_encode( + cryptstate_T *state UNUSED, + char_u *from UNUSED, + size_t len UNUSED, + char_u *to UNUSED, + int last UNUSED) +{ +# ifdef FEAT_SODIUM + // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES + sodium_state_T *sod_st = state->method_state; + unsigned char tag = last + ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0; + + if (sod_st->count == 0) + { + if (len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES) + { + emsg(e_libsodium_cannot_encrypt_header); + return; + } + crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state, + to, sod_st->key); + to += crypto_secretstream_xchacha20poly1305_HEADERBYTES; + } + + if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES) + { + emsg(e_libsodium_cannot_encrypt_buffer); + return; + } + + crypto_secretstream_xchacha20poly1305_push(&sod_st->state, to, NULL, + from, len, NULL, 0, tag); + + sod_st->count++; +# endif +} +#endif + +/* + * Decrypt "from[len]" into "to[len]". + * "from" and "to" can be equal to encrypt in place. + */ +#if 0 // Currently unused + void +crypt_sodium_decode( + cryptstate_T *state UNUSED, + char_u *from UNUSED, + size_t len UNUSED, + char_u *to UNUSED, + int last UNUSED) +{ +# ifdef FEAT_SODIUM + // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES + sodium_state_T *sod_st = state->method_state; + unsigned char tag; + unsigned long long buf_len; + char_u *p1 = from; + char_u *p2 = to; + char_u *buf_out; + + if (sod_st->count == 0 + && len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES) + { + emsg(e_libsodium_cannot_decrypt_header); + return; + } + + buf_out = (char_u *)alloc(len); + + if (buf_out == NULL) + { + emsg(e_libsodium_cannot_allocate_buffer); + return; + } + if (sod_st->count == 0) + { + if (crypto_secretstream_xchacha20poly1305_init_pull( + &sod_st->state, from, sod_st->key) != 0) + { + emsg(e_libsodium_decryption_failed_header_incomplete); + goto fail; + } + + from += crypto_secretstream_xchacha20poly1305_HEADERBYTES; + len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES; + + if (p1 == p2) + to += crypto_secretstream_xchacha20poly1305_HEADERBYTES; + } + + if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES) + { + emsg(e_libsodium_cannot_decrypt_buffer); + goto fail; + } + if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state, + buf_out, &buf_len, &tag, from, len, NULL, 0) != 0) + { + emsg(e_libsodium_decryption_failed); + goto fail; + } + sod_st->count++; + + if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last) + { + emsg(e_libsodium_decryption_failed_premature); + goto fail; + } + if (p1 == p2) + mch_memmove(p2, buf_out, buf_len); + +fail: + vim_free(buf_out); +# endif +} +#endif + +/* + * Encrypt "from[len]" into "to[len]". + * "from" and "to" can be equal to encrypt in place. + */ + static long +crypt_sodium_buffer_encode( + cryptstate_T *state UNUSED, + char_u *from UNUSED, + size_t len UNUSED, + char_u **buf_out UNUSED, + int last UNUSED) +{ +# ifdef FEAT_SODIUM + // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES + unsigned long long out_len; + char_u *ptr; + unsigned char tag = last + ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0; + int length; + sodium_state_T *sod_st = state->method_state; + int first = (sod_st->count == 0); + + length = (int)len + crypto_secretstream_xchacha20poly1305_ABYTES + + (first ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0); + *buf_out = alloc_clear(length); + if (*buf_out == NULL) + { + emsg(e_libsodium_cannot_allocate_buffer); + return -1; + } + ptr = *buf_out; + + if (first) + { + crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state, + ptr, sod_st->key); + ptr += crypto_secretstream_xchacha20poly1305_HEADERBYTES; + } + + crypto_secretstream_xchacha20poly1305_push(&sod_st->state, ptr, + &out_len, from, len, NULL, 0, tag); + + sod_st->count++; + return out_len + (first + ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0); +# else + return -1; +# endif +} + +/* + * Decrypt "from[len]" into "to[len]". + * "from" and "to" can be equal to encrypt in place. + */ + static long +crypt_sodium_buffer_decode( + cryptstate_T *state UNUSED, + char_u *from UNUSED, + size_t len UNUSED, + char_u **buf_out UNUSED, + int last UNUSED) +{ +# ifdef FEAT_SODIUM + // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES + sodium_state_T *sod_st = state->method_state; + unsigned char tag; + unsigned long long out_len; + *buf_out = alloc_clear(len); + if (*buf_out == NULL) + { + emsg(e_libsodium_cannot_allocate_buffer); + return -1; + } + + if (sod_st->count == 0) + { + if (crypto_secretstream_xchacha20poly1305_init_pull(&sod_st->state, + from, sod_st->key) != 0) + { + emsg(e_libsodium_decryption_failed_header_incomplete); + return -1; + } + from += crypto_secretstream_xchacha20poly1305_HEADERBYTES; + len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES; + sod_st->count++; + } + if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state, + *buf_out, &out_len, &tag, from, len, NULL, 0) != 0) + { + emsg(e_libsodium_decryption_failed); + return -1; + } + + if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last) + emsg(e_libsodium_decryption_failed_premature); + return (long) out_len; +# else + return -1; +# endif +} + +# if defined(FEAT_SODIUM) || defined(PROTO) + int +crypt_sodium_munlock(void *const addr, const size_t len) +{ + return sodium_munlock(addr, len); +} + + void +crypt_sodium_randombytes_buf(void *const buf, const size_t size) +{ + randombytes_buf(buf, size); +} + + int +crypt_sodium_init(void) +{ + return sodium_init(); +} + + uint32_t +crypt_sodium_randombytes_random(void) +{ + return randombytes_random(); +} +# endif + +#endif // FEAT_CRYPT diff --git a/src/crypt_zip.c b/src/crypt_zip.c new file mode 100644 index 0000000..91bbd7b --- /dev/null +++ b/src/crypt_zip.c @@ -0,0 +1,157 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * crypt_zip.c: Zip encryption support. + */ +#include "vim.h" + +#if defined(FEAT_CRYPT) || defined(PROTO) +/* + * Optional encryption support. + * Mohsin Ahmed, mosh@sasi.com, 98-09-24 + * Based on zip/crypt sources. + * + * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to + * most countries. There are a few exceptions, but that still should not be a + * problem since this code was originally created in Europe and India. + */ + +// Need a type that should be 32 bits. 64 also works but wastes space. +typedef unsigned int u32_T; // int is at least 32 bits + +// The state of encryption, referenced by cryptstate_T. +typedef struct { + u32_T keys[3]; +} zip_state_T; + + +static u32_T crc_32_table[256]; + +/* + * Fill the CRC table, if not done already. + */ + static void +make_crc_tab(void) +{ + u32_T s, t, v; + static int done = FALSE; + + if (done) + return; + for (t = 0; t < 256; t++) + { + v = t; + for (s = 0; s < 8; s++) + v = (v >> 1) ^ ((v & 1) * (u32_T)0xedb88320L); + crc_32_table[t] = v; + } + done = TRUE; +} + +#define CRC32(c, b) (crc_32_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) + +/* + * Return the next byte in the pseudo-random sequence. + */ +#define DECRYPT_BYTE_ZIP(keys, t) \ +{ \ + short_u temp = (short_u)keys[2] | 2; \ + t = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); \ +} + +/* + * Update the encryption keys with the next byte of plain text. + */ +#define UPDATE_KEYS_ZIP(keys, c) do { \ + keys[0] = CRC32(keys[0], (c)); \ + keys[1] += keys[0] & 0xff; \ + keys[1] = keys[1] * 134775813L + 1; \ + keys[2] = CRC32(keys[2], (int)(keys[1] >> 24)); \ +} while (0) + +/* + * Initialize for encryption/decryption. + */ + int +crypt_zip_init( + cryptstate_T *state, + char_u *key, + char_u *salt UNUSED, + int salt_len UNUSED, + char_u *seed UNUSED, + int seed_len UNUSED) +{ + char_u *p; + zip_state_T *zs; + + zs = ALLOC_ONE(zip_state_T); + if (zs == NULL) + return FAIL; + state->method_state = zs; + + make_crc_tab(); + zs->keys[0] = 305419896L; + zs->keys[1] = 591751049L; + zs->keys[2] = 878082192L; + for (p = key; *p != NUL; ++p) + UPDATE_KEYS_ZIP(zs->keys, (int)*p); + + return OK; +} + +/* + * Encrypt "from[len]" into "to[len]". + * "from" and "to" can be equal to encrypt in place. + */ + void +crypt_zip_encode( + cryptstate_T *state, + char_u *from, + size_t len, + char_u *to, + int last UNUSED) +{ + zip_state_T *zs = state->method_state; + size_t i; + int ztemp, t; + + for (i = 0; i < len; ++i) + { + ztemp = from[i]; + DECRYPT_BYTE_ZIP(zs->keys, t); + UPDATE_KEYS_ZIP(zs->keys, ztemp); + to[i] = t ^ ztemp; + } +} + +/* + * Decrypt "from[len]" into "to[len]". + */ + void +crypt_zip_decode( + cryptstate_T *state, + char_u *from, + size_t len, + char_u *to, + int last UNUSED) +{ + zip_state_T *zs = state->method_state; + size_t i; + short_u temp; + + for (i = 0; i < len; ++i) + { + temp = (short_u)zs->keys[2] | 2; + temp = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); + UPDATE_KEYS_ZIP(zs->keys, to[i] = from[i] ^ temp); + } +} + +#endif // FEAT_CRYPT diff --git a/src/debugger.c b/src/debugger.c new file mode 100644 index 0000000..b158ecd --- /dev/null +++ b/src/debugger.c @@ -0,0 +1,1057 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * debugger.c: Vim script debugger functions + */ + +#include "vim.h" + +#if defined(FEAT_EVAL) || defined(PROTO) +static int debug_greedy = FALSE; // batch mode debugging: don't save + // and restore typeahead. +static void do_setdebugtracelevel(char_u *arg); +static void do_checkbacktracelevel(void); +static void do_showbacktrace(char_u *cmd); + +static char_u *debug_oldval = NULL; // old and newval for debug expressions +static char_u *debug_newval = NULL; +static int debug_expr = 0; // use debug_expr + + int +has_watchexpr(void) +{ + return debug_expr; +} + +/* + * do_debug(): Debug mode. + * Repeatedly get Ex commands, until told to continue normal execution. + */ + void +do_debug(char_u *cmd) +{ + int save_msg_scroll = msg_scroll; + int save_State = State; + int save_did_emsg = did_emsg; + int save_cmd_silent = cmd_silent; + int save_msg_silent = msg_silent; + int save_emsg_silent = emsg_silent; + int save_redir_off = redir_off; + tasave_T typeaheadbuf; + int typeahead_saved = FALSE; + int save_ignore_script = 0; + int save_ex_normal_busy; + int n; + char_u *cmdline = NULL; + char_u *p; + char_u *sname; + char *tail = NULL; + static int last_cmd = 0; +#define CMD_CONT 1 +#define CMD_NEXT 2 +#define CMD_STEP 3 +#define CMD_FINISH 4 +#define CMD_QUIT 5 +#define CMD_INTERRUPT 6 +#define CMD_BACKTRACE 7 +#define CMD_FRAME 8 +#define CMD_UP 9 +#define CMD_DOWN 10 + +#ifdef ALWAYS_USE_GUI + // Can't do this when there is no terminal for input/output. + if (!gui.in_use) + { + // Break as soon as possible. + debug_break_level = 9999; + return; + } +#endif + + // Make sure we are in raw mode and start termcap mode. Might have side + // effects... + settmode(TMODE_RAW); + starttermcap(); + + ++RedrawingDisabled; // don't redisplay the window + ++no_wait_return; // don't wait for return + did_emsg = FALSE; // don't use error from debugged stuff + cmd_silent = FALSE; // display commands + msg_silent = FALSE; // display messages + emsg_silent = FALSE; // display error messages + redir_off = TRUE; // don't redirect debug commands + save_timeout_for_debugging(); // disable regexp timeout flag + + State = MODE_NORMAL; + debug_mode = TRUE; + + if (!debug_did_msg) + msg(_("Entering Debug mode. Type \"cont\" to continue.")); + if (debug_oldval != NULL) + { + smsg(_("Oldval = \"%s\""), debug_oldval); + vim_free(debug_oldval); + debug_oldval = NULL; + } + if (debug_newval != NULL) + { + smsg(_("Newval = \"%s\""), debug_newval); + vim_free(debug_newval); + debug_newval = NULL; + } + sname = estack_sfile(ESTACK_NONE); + if (sname != NULL) + msg((char *)sname); + vim_free(sname); + if (SOURCING_LNUM != 0) + smsg(_("line %ld: %s"), SOURCING_LNUM, cmd); + else + smsg(_("cmd: %s"), cmd); + + // Repeat getting a command and executing it. + for (;;) + { + msg_scroll = TRUE; + need_wait_return = FALSE; + + // Save the current typeahead buffer and replace it with an empty one. + // This makes sure we get input from the user here and don't interfere + // with the commands being executed. Reset "ex_normal_busy" to avoid + // the side effects of using ":normal". Save the stuff buffer and make + // it empty. Set ignore_script to avoid reading from script input. + save_ex_normal_busy = ex_normal_busy; + ex_normal_busy = 0; + if (!debug_greedy) + { + save_typeahead(&typeaheadbuf); + typeahead_saved = TRUE; + save_ignore_script = ignore_script; + ignore_script = TRUE; + } + + // don't debug any function call, e.g. from an expression mapping + n = debug_break_level; + debug_break_level = -1; + + vim_free(cmdline); + cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL); + + debug_break_level = n; + if (typeahead_saved) + { + restore_typeahead(&typeaheadbuf, TRUE); + ignore_script = save_ignore_script; + } + ex_normal_busy = save_ex_normal_busy; + + cmdline_row = msg_row; + msg_starthere(); + if (cmdline != NULL) + { + // If this is a debug command, set "last_cmd". + // If not, reset "last_cmd". + // For a blank line use previous command. + p = skipwhite(cmdline); + if (*p != NUL) + { + switch (*p) + { + case 'c': last_cmd = CMD_CONT; + tail = "ont"; + break; + case 'n': last_cmd = CMD_NEXT; + tail = "ext"; + break; + case 's': last_cmd = CMD_STEP; + tail = "tep"; + break; + case 'f': + last_cmd = 0; + if (p[1] == 'r') + { + last_cmd = CMD_FRAME; + tail = "rame"; + } + else + { + last_cmd = CMD_FINISH; + tail = "inish"; + } + break; + case 'q': last_cmd = CMD_QUIT; + tail = "uit"; + break; + case 'i': last_cmd = CMD_INTERRUPT; + tail = "nterrupt"; + break; + case 'b': last_cmd = CMD_BACKTRACE; + if (p[1] == 't') + tail = "t"; + else + tail = "acktrace"; + break; + case 'w': last_cmd = CMD_BACKTRACE; + tail = "here"; + break; + case 'u': last_cmd = CMD_UP; + tail = "p"; + break; + case 'd': last_cmd = CMD_DOWN; + tail = "own"; + break; + default: last_cmd = 0; + } + if (last_cmd != 0) + { + // Check that the tail matches. + ++p; + while (*p != NUL && *p == *tail) + { + ++p; + ++tail; + } + if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) + last_cmd = 0; + } + } + + if (last_cmd != 0) + { + // Execute debug command: decide where to break next and + // return. + switch (last_cmd) + { + case CMD_CONT: + debug_break_level = -1; + break; + case CMD_NEXT: + debug_break_level = ex_nesting_level; + break; + case CMD_STEP: + debug_break_level = 9999; + break; + case CMD_FINISH: + debug_break_level = ex_nesting_level - 1; + break; + case CMD_QUIT: + got_int = TRUE; + debug_break_level = -1; + break; + case CMD_INTERRUPT: + got_int = TRUE; + debug_break_level = 9999; + // Do not repeat ">interrupt" cmd, continue stepping. + last_cmd = CMD_STEP; + break; + case CMD_BACKTRACE: + do_showbacktrace(cmd); + continue; + case CMD_FRAME: + if (*p == NUL) + { + do_showbacktrace(cmd); + } + else + { + p = skipwhite(p); + do_setdebugtracelevel(p); + } + continue; + case CMD_UP: + debug_backtrace_level++; + do_checkbacktracelevel(); + continue; + case CMD_DOWN: + debug_backtrace_level--; + do_checkbacktracelevel(); + continue; + } + // Going out reset backtrace_level + debug_backtrace_level = 0; + break; + } + + // don't debug this command + n = debug_break_level; + debug_break_level = -1; + (void)do_cmdline(cmdline, getexline, NULL, + DOCMD_VERBOSE|DOCMD_EXCRESET); + debug_break_level = n; + } + lines_left = Rows - 1; + } + vim_free(cmdline); + + --RedrawingDisabled; + --no_wait_return; + redraw_all_later(UPD_NOT_VALID); + need_wait_return = FALSE; + msg_scroll = save_msg_scroll; + restore_timeout_for_debugging(); + lines_left = Rows - 1; + State = save_State; + debug_mode = FALSE; + did_emsg = save_did_emsg; + cmd_silent = save_cmd_silent; + msg_silent = save_msg_silent; + emsg_silent = save_emsg_silent; + redir_off = save_redir_off; + + // Only print the message again when typing a command before coming back + // here. + debug_did_msg = TRUE; +} + + static int +get_maxbacktrace_level(char_u *sname) +{ + char *p, *q; + int maxbacktrace = 0; + + if (sname == NULL) + return 0; + + p = (char *)sname; + while ((q = strstr(p, "..")) != NULL) + { + p = q + 2; + maxbacktrace++; + } + return maxbacktrace; +} + + static void +do_setdebugtracelevel(char_u *arg) +{ + int level; + + level = atoi((char *)arg); + if (*arg == '+' || level < 0) + debug_backtrace_level += level; + else + debug_backtrace_level = level; + + do_checkbacktracelevel(); +} + + static void +do_checkbacktracelevel(void) +{ + if (debug_backtrace_level < 0) + { + debug_backtrace_level = 0; + msg(_("frame is zero")); + } + else + { + char_u *sname = estack_sfile(ESTACK_NONE); + int max = get_maxbacktrace_level(sname); + + if (debug_backtrace_level > max) + { + debug_backtrace_level = max; + smsg(_("frame at highest level: %d"), max); + } + vim_free(sname); + } +} + + static void +do_showbacktrace(char_u *cmd) +{ + char_u *sname; + char *cur; + char *next; + int i = 0; + int max; + + sname = estack_sfile(ESTACK_NONE); + max = get_maxbacktrace_level(sname); + if (sname != NULL) + { + cur = (char *)sname; + while (!got_int) + { + next = strstr(cur, ".."); + if (next != NULL) + *next = NUL; + if (i == max - debug_backtrace_level) + smsg("->%d %s", max - i, cur); + else + smsg(" %d %s", max - i, cur); + ++i; + if (next == NULL) + break; + *next = '.'; + cur = next + 2; + } + vim_free(sname); + } + + if (SOURCING_LNUM != 0) + smsg(_("line %ld: %s"), (long)SOURCING_LNUM, cmd); + else + smsg(_("cmd: %s"), cmd); +} + +/* + * ":debug". + */ + void +ex_debug(exarg_T *eap) +{ + int debug_break_level_save = debug_break_level; + + debug_break_level = 9999; + do_cmdline_cmd(eap->arg); + debug_break_level = debug_break_level_save; +} + +static char_u *debug_breakpoint_name = NULL; +static linenr_T debug_breakpoint_lnum; + +/* + * When debugging or a breakpoint is set on a skipped command, no debug prompt + * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and + * debug_skipped_name is then set to the source name in the breakpoint case. If + * a skipped command decides itself that a debug prompt should be displayed, it + * can do so by calling dbg_check_skipped(). + */ +static int debug_skipped; +static char_u *debug_skipped_name; + +/* + * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is + * at or below the break level. But only when the line is actually + * executed. Return TRUE and set breakpoint_name for skipped commands that + * decide to execute something themselves. + * Called from do_one_cmd() before executing a command. + */ + void +dbg_check_breakpoint(exarg_T *eap) +{ + char_u *p; + + debug_skipped = FALSE; + if (debug_breakpoint_name != NULL) + { + if (!eap->skip) + { + // replace K_SNR with "" + if (debug_breakpoint_name[0] == K_SPECIAL + && debug_breakpoint_name[1] == KS_EXTRA + && debug_breakpoint_name[2] == KE_SNR) + p = (char_u *)""; + else + p = (char_u *)""; + smsg(_("Breakpoint in \"%s%s\" line %ld"), + p, + debug_breakpoint_name + (*p == NUL ? 0 : 3), + (long)debug_breakpoint_lnum); + debug_breakpoint_name = NULL; + do_debug(eap->cmd); + } + else + { + debug_skipped = TRUE; + debug_skipped_name = debug_breakpoint_name; + debug_breakpoint_name = NULL; + } + } + else if (ex_nesting_level <= debug_break_level) + { + if (!eap->skip) + do_debug(eap->cmd); + else + { + debug_skipped = TRUE; + debug_skipped_name = NULL; + } + } +} + +/* + * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was + * set. Return TRUE when the debug mode is entered this time. + */ + int +dbg_check_skipped(exarg_T *eap) +{ + int prev_got_int; + + if (!debug_skipped) + return FALSE; + + // Save the value of got_int and reset it. We don't want a previous + // interruption cause flushing the input buffer. + prev_got_int = got_int; + got_int = FALSE; + debug_breakpoint_name = debug_skipped_name; + // eap->skip is TRUE + eap->skip = FALSE; + (void)dbg_check_breakpoint(eap); + eap->skip = TRUE; + got_int |= prev_got_int; + return TRUE; +} + +/* + * The list of breakpoints: dbg_breakp. + * This is a grow-array of structs. + */ +struct debuggy +{ + int dbg_nr; // breakpoint number + int dbg_type; // DBG_FUNC, DBG_FILE or DBG_EXPR + char_u *dbg_name; // function, expression or file name + regprog_T *dbg_prog; // regexp program + linenr_T dbg_lnum; // line number in function or file + int dbg_forceit; // ! used +#ifdef FEAT_EVAL + typval_T *dbg_val; // last result of watchexpression +#endif + int dbg_level; // stored nested level for expr +}; + +static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL}; +#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx]) +#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx]) +static int last_breakp = 0; // nr of last defined breakpoint +static int has_expr_breakpoint = FALSE; + +#ifdef FEAT_PROFILE +// Profiling uses file and func names similar to breakpoints. +static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL}; +#endif +#define DBG_FUNC 1 +#define DBG_FILE 2 +#define DBG_EXPR 3 + +static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp); + +/* + * Evaluate the "bp->dbg_name" expression and return the result. + * Disables error messages. + */ + static typval_T * +eval_expr_no_emsg(struct debuggy *bp) +{ + typval_T *tv; + + // Disable error messages, a bad expression would make Vim unusable. + ++emsg_off; + tv = eval_expr(bp->dbg_name, NULL); + --emsg_off; + + return tv; +} + +/* + * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them + * in the entry just after the last one in dbg_breakp. Note that "dbg_name" + * is allocated. + * Returns FAIL for failure. + */ + static int +dbg_parsearg( + char_u *arg, + garray_T *gap) // either &dbg_breakp or &prof_ga +{ + char_u *p = arg; + char_u *q; + struct debuggy *bp; + int here = FALSE; + + if (ga_grow(gap, 1) == FAIL) + return FAIL; + bp = &DEBUGGY(gap, gap->ga_len); + + // Find "func" or "file". + if (STRNCMP(p, "func", 4) == 0) + bp->dbg_type = DBG_FUNC; + else if (STRNCMP(p, "file", 4) == 0) + bp->dbg_type = DBG_FILE; + else if ( +#ifdef FEAT_PROFILE + gap != &prof_ga && +#endif + STRNCMP(p, "here", 4) == 0) + { + if (curbuf->b_ffname == NULL) + { + emsg(_(e_no_file_name)); + return FAIL; + } + bp->dbg_type = DBG_FILE; + here = TRUE; + } + else if ( +#ifdef FEAT_PROFILE + gap != &prof_ga && +#endif + STRNCMP(p, "expr", 4) == 0) + bp->dbg_type = DBG_EXPR; + else + { + semsg(_(e_invalid_argument_str), p); + return FAIL; + } + p = skipwhite(p + 4); + + // Find optional line number. + if (here) + bp->dbg_lnum = curwin->w_cursor.lnum; + else if ( +#ifdef FEAT_PROFILE + gap != &prof_ga && +#endif + VIM_ISDIGIT(*p)) + { + bp->dbg_lnum = getdigits(&p); + p = skipwhite(p); + } + else + bp->dbg_lnum = 0; + + // Find the function or file name. Don't accept a function name with (). + if ((!here && *p == NUL) + || (here && *p != NUL) + || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL)) + { + semsg(_(e_invalid_argument_str), arg); + return FAIL; + } + + if (bp->dbg_type == DBG_FUNC) + bp->dbg_name = vim_strsave(STRNCMP(p, "g:", 2) == 0 ? p + 2 : p); + else if (here) + bp->dbg_name = vim_strsave(curbuf->b_ffname); + else if (bp->dbg_type == DBG_EXPR) + { + bp->dbg_name = vim_strsave(p); + if (bp->dbg_name != NULL) + bp->dbg_val = eval_expr_no_emsg(bp); + } + else + { + // Expand the file name in the same way as do_source(). This means + // doing it twice, so that $DIR/file gets expanded when $DIR is + // "~/dir". + q = expand_env_save(p); + if (q == NULL) + return FAIL; + p = expand_env_save(q); + vim_free(q); + if (p == NULL) + return FAIL; + if (*p != '*') + { + bp->dbg_name = fix_fname(p); + vim_free(p); + } + else + bp->dbg_name = p; + } + + if (bp->dbg_name == NULL) + return FAIL; + return OK; +} + +/* + * ":breakadd". Also used for ":profile". + */ + void +ex_breakadd(exarg_T *eap) +{ + struct debuggy *bp; + char_u *pat; + garray_T *gap; + + gap = &dbg_breakp; +#ifdef FEAT_PROFILE + if (eap->cmdidx == CMD_profile) + gap = &prof_ga; +#endif + + if (dbg_parsearg(eap->arg, gap) != OK) + return; + + bp = &DEBUGGY(gap, gap->ga_len); + bp->dbg_forceit = eap->forceit; + + if (bp->dbg_type != DBG_EXPR) + { + pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE); + if (pat != NULL) + { + bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); + vim_free(pat); + } + if (pat == NULL || bp->dbg_prog == NULL) + vim_free(bp->dbg_name); + else + { + if (bp->dbg_lnum == 0) // default line number is 1 + bp->dbg_lnum = 1; +#ifdef FEAT_PROFILE + if (eap->cmdidx != CMD_profile) +#endif + { + DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp; + ++debug_tick; + } + ++gap->ga_len; + } + } + else + { + // DBG_EXPR + DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp; + ++debug_tick; + if (gap == &dbg_breakp) + has_expr_breakpoint = TRUE; + } +} + +/* + * ":debuggreedy". + */ + void +ex_debuggreedy(exarg_T *eap) +{ + if (eap->addr_count == 0 || eap->line2 != 0) + debug_greedy = TRUE; + else + debug_greedy = FALSE; +} + + static void +update_has_expr_breakpoint(void) +{ + int i; + + has_expr_breakpoint = FALSE; + for (i = 0; i < dbg_breakp.ga_len; ++i) + if (BREAKP(i).dbg_type == DBG_EXPR) + { + has_expr_breakpoint = TRUE; + break; + } +} + +/* + * Return TRUE if there is any expression breakpoint. + */ + int +debug_has_expr_breakpoint(void) +{ + return has_expr_breakpoint; +} + +/* + * ":breakdel" and ":profdel". + */ + void +ex_breakdel(exarg_T *eap) +{ + struct debuggy *bp, *bpi; + int nr; + int todel = -1; + int del_all = FALSE; + int i; + linenr_T best_lnum = 0; + garray_T *gap; + + gap = &dbg_breakp; + if (eap->cmdidx == CMD_profdel) + { +#ifdef FEAT_PROFILE + gap = &prof_ga; +#else + ex_ni(eap); + return; +#endif + } + + if (vim_isdigit(*eap->arg)) + { + // ":breakdel {nr}" + nr = atol((char *)eap->arg); + for (i = 0; i < gap->ga_len; ++i) + if (DEBUGGY(gap, i).dbg_nr == nr) + { + todel = i; + break; + } + } + else if (*eap->arg == '*') + { + todel = 0; + del_all = TRUE; + } + else + { + // ":breakdel {func|file|expr} [lnum] {name}" + if (dbg_parsearg(eap->arg, gap) == FAIL) + return; + bp = &DEBUGGY(gap, gap->ga_len); + for (i = 0; i < gap->ga_len; ++i) + { + bpi = &DEBUGGY(gap, i); + if (bp->dbg_type == bpi->dbg_type + && STRCMP(bp->dbg_name, bpi->dbg_name) == 0 + && (bp->dbg_lnum == bpi->dbg_lnum + || (bp->dbg_lnum == 0 + && (best_lnum == 0 + || bpi->dbg_lnum < best_lnum)))) + { + todel = i; + best_lnum = bpi->dbg_lnum; + } + } + vim_free(bp->dbg_name); + } + + if (todel < 0) + { + semsg(_(e_breakpoint_not_found_str), eap->arg); + return; + } + + while (gap->ga_len > 0) + { + vim_free(DEBUGGY(gap, todel).dbg_name); +#ifdef FEAT_EVAL + if (DEBUGGY(gap, todel).dbg_type == DBG_EXPR + && DEBUGGY(gap, todel).dbg_val != NULL) + free_tv(DEBUGGY(gap, todel).dbg_val); +#endif + vim_regfree(DEBUGGY(gap, todel).dbg_prog); + --gap->ga_len; + if (todel < gap->ga_len) + mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1), + (gap->ga_len - todel) * sizeof(struct debuggy)); +#ifdef FEAT_PROFILE + if (eap->cmdidx == CMD_breakdel) +#endif + ++debug_tick; + if (!del_all) + break; + } + + // If all breakpoints were removed clear the array. + if (gap->ga_len == 0) + ga_clear(gap); + if (gap == &dbg_breakp) + update_has_expr_breakpoint(); +} + +/* + * ":breaklist". + */ + void +ex_breaklist(exarg_T *eap UNUSED) +{ + struct debuggy *bp; + int i; + + if (dbg_breakp.ga_len == 0) + { + msg(_("No breakpoints defined")); + return; + } + + for (i = 0; i < dbg_breakp.ga_len; ++i) + { + bp = &BREAKP(i); + if (bp->dbg_type == DBG_FILE) + home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE); + if (bp->dbg_type != DBG_EXPR) + smsg(_("%3d %s %s line %ld"), + bp->dbg_nr, + bp->dbg_type == DBG_FUNC ? "func" : "file", + bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff, + (long)bp->dbg_lnum); + else + smsg(_("%3d expr %s"), + bp->dbg_nr, bp->dbg_name); + } +} + +/* + * Find a breakpoint for a function or sourced file. + * Returns line number at which to break; zero when no matching breakpoint. + */ + linenr_T +dbg_find_breakpoint( + int file, // TRUE for a file, FALSE for a function + char_u *fname, // file or function name + linenr_T after) // after this line number +{ + return debuggy_find(file, fname, after, &dbg_breakp, NULL); +} + +#if defined(FEAT_PROFILE) || defined(PROTO) +/* + * Return TRUE if profiling is on for a function or sourced file. + */ + int +has_profiling( + int file, // TRUE for a file, FALSE for a function + char_u *fname, // file or function name + int *fp) // return: forceit +{ + return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp) + != (linenr_T)0); +} +#endif + +/* + * Common code for dbg_find_breakpoint() and has_profiling(). + */ + static linenr_T +debuggy_find( + int is_file, // TRUE for a file, FALSE for a function + char_u *fname, // file or function name + linenr_T after, // after this line number + garray_T *gap, // either &dbg_breakp or &prof_ga + int *fp) // if not NULL: return forceit +{ + struct debuggy *bp; + int i; + linenr_T lnum = 0; + char_u *name = NULL; + char_u *short_name = fname; + int prev_got_int; + + // Return quickly when there are no breakpoints. + if (gap->ga_len == 0) + return (linenr_T)0; + + // For a script-local function remove the prefix, so that + // "profile func Func" matches "Func" in any script. Otherwise it's very + // difficult to profile/debug a script-local function. It may match a + // function in the wrong script, but that is much better than not being + // able to profile/debug a function in a script with unknown ID. + // Also match a script-specific name. + if (!is_file && fname[0] == K_SPECIAL) + { + short_name = vim_strchr(fname, '_') + 1; + name = alloc(STRLEN(fname) + 3); + if (name != NULL) + { + STRCPY(name, ""); + STRCPY(name + 5, fname + 3); + } + } + + for (i = 0; i < gap->ga_len; ++i) + { + // Skip entries that are not useful or are for a line that is beyond + // an already found breakpoint. + bp = &DEBUGGY(gap, i); + if (((bp->dbg_type == DBG_FILE) == is_file + && bp->dbg_type != DBG_EXPR && ( +#ifdef FEAT_PROFILE + gap == &prof_ga || +#endif + (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum))))) + { + // Save the value of got_int and reset it. We don't want a + // previous interruption cancel matching, only hitting CTRL-C + // while matching should abort it. + prev_got_int = got_int; + got_int = FALSE; + if ((name != NULL + && vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0)) + || vim_regexec_prog(&bp->dbg_prog, FALSE, + short_name, (colnr_T)0)) + { + lnum = bp->dbg_lnum; + if (fp != NULL) + *fp = bp->dbg_forceit; + } + got_int |= prev_got_int; + } +#ifdef FEAT_EVAL + else if (bp->dbg_type == DBG_EXPR) + { + typval_T *tv; + int line = FALSE; + + tv = eval_expr_no_emsg(bp); + if (tv != NULL) + { + if (bp->dbg_val == NULL) + { + debug_oldval = typval_tostring(NULL, TRUE); + bp->dbg_val = tv; + debug_newval = typval_tostring(bp->dbg_val, TRUE); + line = TRUE; + } + else + { + // Use "==" instead of "is" for strings, that is what we + // always have done. + exprtype_T type = tv->v_type == VAR_STRING + ? EXPR_EQUAL : EXPR_IS; + + if (typval_compare(tv, bp->dbg_val, type, FALSE) == OK + && tv->vval.v_number == FALSE) + { + typval_T *v; + + line = TRUE; + debug_oldval = typval_tostring(bp->dbg_val, TRUE); + // Need to evaluate again, typval_compare() overwrites + // "tv". + v = eval_expr_no_emsg(bp); + debug_newval = typval_tostring(v, TRUE); + free_tv(bp->dbg_val); + bp->dbg_val = v; + } + free_tv(tv); + } + } + else if (bp->dbg_val != NULL) + { + debug_oldval = typval_tostring(bp->dbg_val, TRUE); + debug_newval = typval_tostring(NULL, TRUE); + free_tv(bp->dbg_val); + bp->dbg_val = NULL; + line = TRUE; + } + + if (line) + { + lnum = after > 0 ? after : 1; + break; + } + } +#endif + } + if (name != fname) + vim_free(name); + + return lnum; +} + +/* + * Called when a breakpoint was encountered. + */ + void +dbg_breakpoint(char_u *name, linenr_T lnum) +{ + // We need to check if this line is actually executed in do_one_cmd() + debug_breakpoint_name = name; + debug_breakpoint_lnum = lnum; +} +#endif diff --git a/src/dict.c b/src/dict.c new file mode 100644 index 0000000..6941845 --- /dev/null +++ b/src/dict.c @@ -0,0 +1,1620 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * dict.c: Dictionary support + */ + +#include "vim.h" + +#if defined(FEAT_EVAL) || defined(PROTO) + +// List head for garbage collection. Although there can be a reference loop +// from partial to dict to partial, we don't need to keep track of the partial, +// since it will get freed when the dict is unused and gets freed. +static dict_T *first_dict = NULL; + +/* + * Allocate an empty header for a dictionary. + * Caller should take care of the reference count. + */ + dict_T * +dict_alloc(void) +{ + dict_T *d; + + d = ALLOC_CLEAR_ONE(dict_T); + if (d == NULL) + return NULL; + + // Add the dict to the list of dicts for garbage collection. + if (first_dict != NULL) + first_dict->dv_used_prev = d; + d->dv_used_next = first_dict; + d->dv_used_prev = NULL; + first_dict = d; + + hash_init(&d->dv_hashtab); + d->dv_lock = 0; + d->dv_scope = 0; + d->dv_refcount = 0; + d->dv_copyID = 0; + return d; +} + +/* + * dict_alloc() with an ID for alloc_fail(). + */ + dict_T * +dict_alloc_id(alloc_id_T id UNUSED) +{ +#ifdef FEAT_EVAL + if (alloc_fail_id == id && alloc_does_fail(sizeof(list_T))) + return NULL; +#endif + return (dict_alloc()); +} + + dict_T * +dict_alloc_lock(int lock) +{ + dict_T *d = dict_alloc(); + + if (d != NULL) + d->dv_lock = lock; + return d; +} + +/* + * Allocate an empty dict for a return value. + * Returns OK or FAIL. + */ + int +rettv_dict_alloc(typval_T *rettv) +{ + dict_T *d = dict_alloc_lock(0); + + if (d == NULL) + return FAIL; + + rettv_dict_set(rettv, d); + return OK; +} + +/* + * Set a dictionary as the return value + */ + void +rettv_dict_set(typval_T *rettv, dict_T *d) +{ + rettv->v_type = VAR_DICT; + rettv->vval.v_dict = d; + if (d != NULL) + ++d->dv_refcount; +} + +/* + * Free a Dictionary, including all non-container items it contains. + * Ignores the reference count. + */ + void +dict_free_contents(dict_T *d) +{ + hashtab_free_contents(&d->dv_hashtab); + free_type(d->dv_type); + d->dv_type = NULL; +} + +/* + * Clear hashtab "ht" and dict items it contains. + * If "ht" is not freed then you should call hash_init() next! + */ + void +hashtab_free_contents(hashtab_T *ht) +{ + int todo; + hashitem_T *hi; + dictitem_T *di; + + if (check_hashtab_frozen(ht, "clear dict")) + return; + + // Lock the hashtab, we don't want it to resize while freeing items. + hash_lock(ht); + todo = (int)ht->ht_used; + for (hi = ht->ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + // Remove the item before deleting it, just in case there is + // something recursive causing trouble. + di = HI2DI(hi); + hash_remove(ht, hi, "clear dict"); + dictitem_free(di); + --todo; + } + } + + // The hashtab is still locked, it has to be re-initialized anyway. + hash_clear(ht); +} + + static void +dict_free_dict(dict_T *d) +{ + // Remove the dict from the list of dicts for garbage collection. + if (d->dv_used_prev == NULL) + first_dict = d->dv_used_next; + else + d->dv_used_prev->dv_used_next = d->dv_used_next; + if (d->dv_used_next != NULL) + d->dv_used_next->dv_used_prev = d->dv_used_prev; + vim_free(d); +} + + static void +dict_free(dict_T *d) +{ + if (!in_free_unref_items) + { + dict_free_contents(d); + dict_free_dict(d); + } +} + +/* + * Unreference a Dictionary: decrement the reference count and free it when it + * becomes zero. + */ + void +dict_unref(dict_T *d) +{ + if (d != NULL && --d->dv_refcount <= 0) + dict_free(d); +} + +/* + * Go through the list of dicts and free items without the copyID. + * Returns TRUE if something was freed. + */ + int +dict_free_nonref(int copyID) +{ + dict_T *dd; + int did_free = FALSE; + + for (dd = first_dict; dd != NULL; dd = dd->dv_used_next) + if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) + { + // Free the Dictionary and ordinary items it contains, but don't + // recurse into Lists and Dictionaries, they will be in the list + // of dicts or list of lists. + dict_free_contents(dd); + did_free = TRUE; + } + return did_free; +} + + void +dict_free_items(int copyID) +{ + dict_T *dd, *dd_next; + + for (dd = first_dict; dd != NULL; dd = dd_next) + { + dd_next = dd->dv_used_next; + if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) + dict_free_dict(dd); + } +} + +/* + * Allocate a Dictionary item. + * The "key" is copied to the new item. + * Note that the type and value of the item "di_tv" still needs to be + * initialized! + * Returns NULL when out of memory. + */ + dictitem_T * +dictitem_alloc(char_u *key) +{ + dictitem_T *di; + size_t len = STRLEN(key); + + di = alloc(offsetof(dictitem_T, di_key) + len + 1); + if (di == NULL) + return NULL; + + mch_memmove(di->di_key, key, len + 1); + di->di_flags = DI_FLAGS_ALLOC; + di->di_tv.v_lock = 0; + di->di_tv.v_type = VAR_UNKNOWN; + return di; +} + +/* + * Make a copy of a Dictionary item. + */ + static dictitem_T * +dictitem_copy(dictitem_T *org) +{ + dictitem_T *di; + size_t len = STRLEN(org->di_key); + + di = alloc(offsetof(dictitem_T, di_key) + len + 1); + if (di == NULL) + return NULL; + + mch_memmove(di->di_key, org->di_key, len + 1); + di->di_flags = DI_FLAGS_ALLOC; + copy_tv(&org->di_tv, &di->di_tv); + return di; +} + +/* + * Remove item "item" from Dictionary "dict" and free it. + * "command" is used for the error message when the hashtab if frozen. + */ + void +dictitem_remove(dict_T *dict, dictitem_T *item, char *command) +{ + hashitem_T *hi; + + hi = hash_find(&dict->dv_hashtab, item->di_key); + if (HASHITEM_EMPTY(hi)) + internal_error("dictitem_remove()"); + else + hash_remove(&dict->dv_hashtab, hi, command); + dictitem_free(item); +} + +/* + * Free a dict item. Also clears the value. + */ + void +dictitem_free(dictitem_T *item) +{ + clear_tv(&item->di_tv); + if (item->di_flags & DI_FLAGS_ALLOC) + vim_free(item); +} + +/* + * Make a copy of dict "d". Shallow if "deep" is FALSE. + * The refcount of the new dict is set to 1. + * See item_copy() for "top" and "copyID". + * Returns NULL when out of memory. + */ + dict_T * +dict_copy(dict_T *orig, int deep, int top, int copyID) +{ + dict_T *copy; + dictitem_T *di; + int todo; + hashitem_T *hi; + + if (orig == NULL) + return NULL; + + copy = dict_alloc(); + if (copy == NULL) + return NULL; + + if (copyID != 0) + { + orig->dv_copyID = copyID; + orig->dv_copydict = copy; + } + if (orig->dv_type == NULL || top || deep) + copy->dv_type = NULL; + else + copy->dv_type = alloc_type(orig->dv_type); + + todo = (int)orig->dv_hashtab.ht_used; + for (hi = orig->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + --todo; + + di = dictitem_alloc(hi->hi_key); + if (di == NULL) + break; + if (deep) + { + if (item_copy(&HI2DI(hi)->di_tv, &di->di_tv, + deep, FALSE, copyID) == FAIL) + { + vim_free(di); + break; + } + } + else + copy_tv(&HI2DI(hi)->di_tv, &di->di_tv); + if (dict_add(copy, di) == FAIL) + { + dictitem_free(di); + break; + } + } + } + + ++copy->dv_refcount; + if (todo > 0) + { + dict_unref(copy); + copy = NULL; + } + + return copy; +} + +/* + * Check for adding a function to g: or s: (in Vim9 script) or l:. + * If the name is wrong give an error message and return TRUE. + */ + int +dict_wrong_func_name(dict_T *d, typval_T *tv, char_u *name) +{ + return (d == get_globvar_dict() + || (in_vim9script() && SCRIPT_ID_VALID(current_sctx.sc_sid) + && d == &SCRIPT_ITEM(current_sctx.sc_sid)->sn_vars->sv_dict) + || &d->dv_hashtab == get_funccal_local_ht()) + && (tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) + && var_wrong_func_name(name, TRUE); +} + +/* + * Add item "item" to Dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + int +dict_add(dict_T *d, dictitem_T *item) +{ + if (dict_wrong_func_name(d, &item->di_tv, item->di_key)) + return FAIL; + return hash_add(&d->dv_hashtab, item->di_key, "add to dictionary"); +} + +/* + * Add a number or special entry to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + static int +dict_add_number_special(dict_T *d, char *key, varnumber_T nr, vartype_T vartype) +{ + dictitem_T *item; + + item = dictitem_alloc((char_u *)key); + if (item == NULL) + return FAIL; + item->di_tv.v_type = vartype; + item->di_tv.vval.v_number = nr; + if (dict_add(d, item) == FAIL) + { + dictitem_free(item); + return FAIL; + } + return OK; +} + +/* + * Add a number entry to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + int +dict_add_number(dict_T *d, char *key, varnumber_T nr) +{ + return dict_add_number_special(d, key, nr, VAR_NUMBER); +} + +/* + * Add a special entry to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + int +dict_add_bool(dict_T *d, char *key, varnumber_T nr) +{ + return dict_add_number_special(d, key, nr, VAR_BOOL); +} + +/* + * Add a string entry to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + int +dict_add_string(dict_T *d, char *key, char_u *str) +{ + return dict_add_string_len(d, key, str, -1); +} + +/* + * Add a string entry to dictionary "d". + * "str" will be copied to allocated memory. + * When "len" is -1 use the whole string, otherwise only this many bytes. + * Returns FAIL when out of memory and when key already exists. + */ + int +dict_add_string_len(dict_T *d, char *key, char_u *str, int len) +{ + dictitem_T *item; + char_u *val = NULL; + + item = dictitem_alloc((char_u *)key); + if (item == NULL) + return FAIL; + item->di_tv.v_type = VAR_STRING; + if (str != NULL) + { + if (len == -1) + val = vim_strsave(str); + else + val = vim_strnsave(str, len); + } + item->di_tv.vval.v_string = val; + if (dict_add(d, item) == FAIL) + { + dictitem_free(item); + return FAIL; + } + return OK; +} + +/* + * Add a list entry to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + int +dict_add_list(dict_T *d, char *key, list_T *list) +{ + dictitem_T *item; + + item = dictitem_alloc((char_u *)key); + if (item == NULL) + return FAIL; + item->di_tv.v_type = VAR_LIST; + item->di_tv.vval.v_list = list; + ++list->lv_refcount; + if (dict_add(d, item) == FAIL) + { + dictitem_free(item); + return FAIL; + } + return OK; +} + +/* + * Add a typval_T entry to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + int +dict_add_tv(dict_T *d, char *key, typval_T *tv) +{ + dictitem_T *item; + + item = dictitem_alloc((char_u *)key); + if (item == NULL) + return FAIL; + copy_tv(tv, &item->di_tv); + if (dict_add(d, item) == FAIL) + { + dictitem_free(item); + return FAIL; + } + return OK; +} + +/* + * Add a callback to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + int +dict_add_callback(dict_T *d, char *key, callback_T *cb) +{ + dictitem_T *item; + + item = dictitem_alloc((char_u *)key); + if (item == NULL) + return FAIL; + put_callback(cb, &item->di_tv); + if (dict_add(d, item) == FAIL) + { + dictitem_free(item); + return FAIL; + } + return OK; +} + +/* + * Initializes "iter" for iterating over dictionary items with + * dict_iterate_next(). + * If "var" is not a Dict or an empty Dict then there will be nothing to + * iterate over, no error is given. + * NOTE: The dictionary must not change until iterating is finished! + */ + void +dict_iterate_start(typval_T *var, dict_iterator_T *iter) +{ + if (var->v_type != VAR_DICT || var->vval.v_dict == NULL) + iter->dit_todo = 0; + else + { + dict_T *d = var->vval.v_dict; + + iter->dit_todo = d->dv_hashtab.ht_used; + iter->dit_hi = d->dv_hashtab.ht_array; + } +} + +/* + * Iterate over the items referred to by "iter". It should be initialized with + * dict_iterate_start(). + * Returns a pointer to the key. + * "*tv_result" is set to point to the value for that key. + * If there are no more items, NULL is returned. + */ + char_u * +dict_iterate_next(dict_iterator_T *iter, typval_T **tv_result) +{ + dictitem_T *di; + char_u *result; + + if (iter->dit_todo == 0) + return NULL; + + while (HASHITEM_EMPTY(iter->dit_hi)) + ++iter->dit_hi; + + di = HI2DI(iter->dit_hi); + result = di->di_key; + *tv_result = &di->di_tv; + + --iter->dit_todo; + ++iter->dit_hi; + return result; +} + +/* + * Add a dict entry to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + int +dict_add_dict(dict_T *d, char *key, dict_T *dict) +{ + dictitem_T *item; + + item = dictitem_alloc((char_u *)key); + if (item == NULL) + return FAIL; + item->di_tv.v_type = VAR_DICT; + item->di_tv.vval.v_dict = dict; + ++dict->dv_refcount; + if (dict_add(d, item) == FAIL) + { + dictitem_free(item); + return FAIL; + } + return OK; +} + +/* + * Get the number of items in a Dictionary. + */ + long +dict_len(dict_T *d) +{ + if (d == NULL) + return 0L; + return (long)d->dv_hashtab.ht_used; +} + +/* + * Find item "key[len]" in Dictionary "d". + * If "len" is negative use strlen(key). + * Returns NULL when not found. + */ + dictitem_T * +dict_find(dict_T *d, char_u *key, int len) +{ +#define AKEYLEN 200 + char_u buf[AKEYLEN]; + char_u *akey; + char_u *tofree = NULL; + hashitem_T *hi; + + if (d == NULL) + return NULL; + if (len < 0) + akey = key; + else if (len >= AKEYLEN) + { + tofree = akey = vim_strnsave(key, len); + if (akey == NULL) + return NULL; + } + else + { + // Avoid a malloc/free by using buf[]. + vim_strncpy(buf, key, len); + akey = buf; + } + + hi = hash_find(&d->dv_hashtab, akey); + vim_free(tofree); + if (HASHITEM_EMPTY(hi)) + return NULL; + return HI2DI(hi); +} + +/* + * Returns TRUE if "key" is present in Dictionary "d". + */ + int +dict_has_key(dict_T *d, char *key) +{ + return dict_find(d, (char_u *)key, -1) != NULL; +} + +/* + * Get a typval_T item from a dictionary and copy it into "rettv". + * Returns FAIL if the entry doesn't exist or out of memory. + */ + int +dict_get_tv(dict_T *d, char *key, typval_T *rettv) +{ + dictitem_T *di; + + di = dict_find(d, (char_u *)key, -1); + if (di == NULL) + return FAIL; + copy_tv(&di->di_tv, rettv); + return OK; +} + +/* + * Get a string item from a dictionary. + * When "save" is TRUE allocate memory for it. + * When FALSE a shared buffer is used, can only be used once! + * Returns NULL if the entry doesn't exist or out of memory. + */ + char_u * +dict_get_string(dict_T *d, char *key, int save) +{ + dictitem_T *di; + char_u *s; + + di = dict_find(d, (char_u *)key, -1); + if (di == NULL) + return NULL; + s = tv_get_string(&di->di_tv); + if (save && s != NULL) + s = vim_strsave(s); + return s; +} + +/* + * Get a number item from a dictionary. + * Returns 0 if the entry doesn't exist. + */ + varnumber_T +dict_get_number(dict_T *d, char *key) +{ + return dict_get_number_def(d, key, 0); +} + +/* + * Get a number item from a dictionary. + * Returns "def" if the entry doesn't exist. + */ + varnumber_T +dict_get_number_def(dict_T *d, char *key, int def) +{ + dictitem_T *di; + + di = dict_find(d, (char_u *)key, -1); + if (di == NULL) + return def; + return tv_get_number(&di->di_tv); +} + +/* + * Get a number item from a dictionary. + * Returns 0 if the entry doesn't exist. + * Give an error if the entry is not a number. + */ + varnumber_T +dict_get_number_check(dict_T *d, char_u *key) +{ + dictitem_T *di; + + di = dict_find(d, key, -1); + if (di == NULL) + return 0; + if (di->di_tv.v_type != VAR_NUMBER) + { + semsg(_(e_invalid_argument_str), tv_get_string(&di->di_tv)); + return 0; + } + return tv_get_number(&di->di_tv); +} + +/* + * Get a bool item (number or true/false) from a dictionary. + * Returns "def" if the entry doesn't exist. + */ + varnumber_T +dict_get_bool(dict_T *d, char *key, int def) +{ + dictitem_T *di; + + di = dict_find(d, (char_u *)key, -1); + if (di == NULL) + return def; + return tv_get_bool(&di->di_tv); +} + +/* + * Return an allocated string with the string representation of a Dictionary. + * May return NULL. + */ + char_u * +dict2string(typval_T *tv, int copyID, int restore_copyID) +{ + garray_T ga; + int first = TRUE; + char_u *tofree; + char_u numbuf[NUMBUFLEN]; + hashitem_T *hi; + char_u *s; + dict_T *d; + int todo; + + if ((d = tv->vval.v_dict) == NULL) + return NULL; + ga_init2(&ga, sizeof(char), 80); + ga_append(&ga, '{'); + + todo = (int)d->dv_hashtab.ht_used; + for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + --todo; + + if (first) + first = FALSE; + else + ga_concat(&ga, (char_u *)", "); + + tofree = string_quote(hi->hi_key, FALSE); + if (tofree != NULL) + { + ga_concat(&ga, tofree); + vim_free(tofree); + } + ga_concat(&ga, (char_u *)": "); + s = echo_string_core(&HI2DI(hi)->di_tv, &tofree, numbuf, copyID, + FALSE, restore_copyID, TRUE); + if (s != NULL) + ga_concat(&ga, s); + vim_free(tofree); + if (s == NULL || did_echo_string_emsg) + break; + line_breakcheck(); + + } + } + if (todo > 0) + { + vim_free(ga.ga_data); + return NULL; + } + + ga_append(&ga, '}'); + ga_append(&ga, NUL); + return (char_u *)ga.ga_data; +} + +/* + * Advance over a literal key, including "-". If the first character is not a + * literal key character then "key" is returned. + */ + static char_u * +skip_literal_key(char_u *key) +{ + char_u *p; + + for (p = key; ASCII_ISALNUM(*p) || *p == '_' || *p == '-'; ++p) + ; + return p; +} + +/* + * Get the key for #{key: val} into "tv" and advance "arg". + * Return FAIL when there is no valid key. + */ + static int +get_literal_key_tv(char_u **arg, typval_T *tv) +{ + char_u *p = skip_literal_key(*arg); + + if (p == *arg) + return FAIL; + tv->v_type = VAR_STRING; + tv->vval.v_string = vim_strnsave(*arg, p - *arg); + + *arg = p; + return OK; +} + +/* + * Get a literal key for a Vim9 dict: + * {"name": value}, + * {'name': value}, + * {name: value} use "name" as a literal key + * Return the key in allocated memory or NULL in the case of an error. + * "arg" is advanced to just after the key. + */ + char_u * +get_literal_key(char_u **arg) +{ + char_u *key; + char_u *end; + typval_T rettv; + + if (**arg == '\'') + { + if (eval_lit_string(arg, &rettv, TRUE, FALSE) == FAIL) + return NULL; + key = rettv.vval.v_string; + } + else if (**arg == '"') + { + if (eval_string(arg, &rettv, TRUE, FALSE) == FAIL) + return NULL; + key = rettv.vval.v_string; + } + else + { + end = skip_literal_key(*arg); + if (end == *arg) + { + semsg(_(e_invalid_key_str), *arg); + return NULL; + } + key = vim_strnsave(*arg, end - *arg); + *arg = end; + } + return key; +} + +/* + * Allocate a variable for a Dictionary and fill it from "*arg". + * "*arg" points to the "{". + * "literal" is TRUE for #{key: val} + * Return OK or FAIL. Returns NOTDONE for {expr}. + */ + int +eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal) +{ + int evaluate = evalarg == NULL ? FALSE + : evalarg->eval_flags & EVAL_EVALUATE; + dict_T *d = NULL; + typval_T tvkey; + typval_T tv; + char_u *key = NULL; + dictitem_T *item; + char_u *curly_expr = skipwhite(*arg + 1); + char_u buf[NUMBUFLEN]; + int vim9script = in_vim9script(); + int had_comma; + + // First check if it's not a curly-braces expression: {expr}. + // Must do this without evaluating, otherwise a function may be called + // twice. Unfortunately this means we need to call eval1() twice for the + // first item. + // "{}" is an empty Dictionary. + // "#{abc}" is never a curly-braces expression. + if (!vim9script + && *curly_expr != '}' + && !literal + && eval1(&curly_expr, &tv, NULL) == OK + && *skipwhite(curly_expr) == '}') + return NOTDONE; + + if (evaluate) + { + d = dict_alloc(); + if (d == NULL) + return FAIL; + } + tvkey.v_type = VAR_UNKNOWN; + tv.v_type = VAR_UNKNOWN; + + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); + while (**arg != '}' && **arg != NUL) + { + int has_bracket = vim9script && **arg == '['; + + if (literal) + { + if (get_literal_key_tv(arg, &tvkey) == FAIL) + goto failret; + } + else if (vim9script && !has_bracket) + { + tvkey.vval.v_string = get_literal_key(arg); + if (tvkey.vval.v_string == NULL) + goto failret; + tvkey.v_type = VAR_STRING; + } + else + { + if (has_bracket) + *arg = skipwhite(*arg + 1); + if (eval1(arg, &tvkey, evalarg) == FAIL) // recursive! + goto failret; + if (has_bracket) + { + *arg = skipwhite(*arg); + if (**arg != ']') + { + emsg(_(e_missing_matching_bracket_after_dict_key)); + clear_tv(&tvkey); + return FAIL; + } + ++*arg; + } + } + + // the colon should come right after the key, but this wasn't checked + // previously, so only require it in Vim9 script. + if (!vim9script) + *arg = skipwhite(*arg); + if (**arg != ':') + { + if (*skipwhite(*arg) == ':') + semsg(_(e_no_white_space_allowed_before_str_str), ":", *arg); + else + semsg(_(e_missing_colon_in_dictionary_str), *arg); + clear_tv(&tvkey); + goto failret; + } + if (evaluate) + { + if (tvkey.v_type == VAR_FLOAT) + { + tvkey.vval.v_string = typval_tostring(&tvkey, TRUE); + tvkey.v_type = VAR_STRING; + } + key = tv_get_string_buf_chk(&tvkey, buf); + if (key == NULL) + { + // "key" is NULL when tv_get_string_buf_chk() gave an errmsg + clear_tv(&tvkey); + goto failret; + } + } + if (vim9script && (*arg)[1] != NUL && !VIM_ISWHITE((*arg)[1])) + { + semsg(_(e_white_space_required_after_str_str), ":", *arg); + clear_tv(&tvkey); + goto failret; + } + + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); + if (eval1(arg, &tv, evalarg) == FAIL) // recursive! + { + if (evaluate) + clear_tv(&tvkey); + goto failret; + } + if (evaluate) + { + item = dict_find(d, key, -1); + if (item != NULL) + { + semsg(_(e_duplicate_key_in_dictionary_str), key); + clear_tv(&tvkey); + clear_tv(&tv); + goto failret; + } + item = dictitem_alloc(key); + if (item != NULL) + { + item->di_tv = tv; + item->di_tv.v_lock = 0; + if (dict_add(d, item) == FAIL) + dictitem_free(item); + } + } + clear_tv(&tvkey); + + // the comma should come right after the value, but this wasn't checked + // previously, so only require it in Vim9 script. + if (!vim9script) + *arg = skipwhite(*arg); + had_comma = **arg == ','; + if (had_comma) + { + if (vim9script && (*arg)[1] != NUL && !VIM_ISWHITE((*arg)[1])) + { + semsg(_(e_white_space_required_after_str_str), ",", *arg); + goto failret; + } + *arg = skipwhite(*arg + 1); + } + + // the "}" can be on the next line + *arg = skipwhite_and_linebreak(*arg, evalarg); + if (**arg == '}') + break; + if (!had_comma) + { + if (**arg == ',') + semsg(_(e_no_white_space_allowed_before_str_str), ",", *arg); + else + semsg(_(e_missing_comma_in_dictionary_str), *arg); + goto failret; + } + } + + if (**arg != '}') + { + if (evalarg != NULL) + semsg(_(e_missing_dict_end_str), *arg); +failret: + if (d != NULL) + dict_free(d); + return FAIL; + } + + *arg = *arg + 1; + if (evaluate) + rettv_dict_set(rettv, d); + + return OK; +} + +/* + * Go over all entries in "d2" and add them to "d1". + * When "action" is "error" then a duplicate key is an error. + * When "action" is "force" then a duplicate key is overwritten. + * When "action" is "move" then move items instead of copying. + * Otherwise duplicate keys are ignored ("action" is "keep"). + * "func_name" is used for reporting where an error occurred. + */ + void +dict_extend(dict_T *d1, dict_T *d2, char_u *action, char *func_name) +{ + dictitem_T *di1; + int todo; + char_u *arg_errmsg = (char_u *)N_("extend() argument"); + type_T *type; + + if (check_hashtab_frozen(&d1->dv_hashtab, "extend")) + return; + + if (*action == 'm') + { + if (check_hashtab_frozen(&d2->dv_hashtab, "extend")) + return; + hash_lock(&d2->dv_hashtab); // don't rehash on hash_remove() + } + + if (d1->dv_type != NULL && d1->dv_type->tt_member != NULL) + type = d1->dv_type->tt_member; + else + type = NULL; + + todo = (int)d2->dv_hashtab.ht_used; + for (hashitem_T *hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) + { + if (!HASHITEM_EMPTY(hi2)) + { + --todo; + di1 = dict_find(d1, hi2->hi_key, -1); + // Check the key to be valid when adding to any scope. + if (d1->dv_scope != 0 && !valid_varname(hi2->hi_key, -1, TRUE)) + break; + + if (type != NULL + && check_typval_arg_type(type, &HI2DI(hi2)->di_tv, + func_name, 0) == FAIL) + break; + + if (di1 == NULL) + { + if (*action == 'm') + { + // Cheap way to move a dict item from "d2" to "d1". + // If dict_add() fails then "d2" won't be empty. + di1 = HI2DI(hi2); + if (dict_add(d1, di1) == OK) + hash_remove(&d2->dv_hashtab, hi2, "extend"); + } + else + { + di1 = dictitem_copy(HI2DI(hi2)); + if (di1 != NULL && dict_add(d1, di1) == FAIL) + dictitem_free(di1); + } + } + else if (*action == 'e') + { + semsg(_(e_key_already_exists_str), hi2->hi_key); + break; + } + else if (*action == 'f' && HI2DI(hi2) != di1) + { + if (value_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE) + || var_check_ro(di1->di_flags, arg_errmsg, TRUE)) + break; + // Disallow replacing a builtin function. + if (dict_wrong_func_name(d1, &HI2DI(hi2)->di_tv, hi2->hi_key)) + break; + clear_tv(&di1->di_tv); + copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv); + } + } + } + + if (*action == 'm') + hash_unlock(&d2->dv_hashtab); +} + +/* + * Return the dictitem that an entry in a hashtable points to. + */ + dictitem_T * +dict_lookup(hashitem_T *hi) +{ + return HI2DI(hi); +} + +/* + * Return TRUE when two dictionaries have exactly the same key/values. + */ + int +dict_equal( + dict_T *d1, + dict_T *d2, + int ic, // ignore case for strings + int recursive) // TRUE when used recursively +{ + hashitem_T *hi; + dictitem_T *item2; + int todo; + + if (d1 == d2) + return TRUE; + if (dict_len(d1) != dict_len(d2)) + return FALSE; + if (dict_len(d1) == 0) + // empty and NULL dicts are considered equal + return TRUE; + if (d1 == NULL || d2 == NULL) + return FALSE; + + todo = (int)d1->dv_hashtab.ht_used; + for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + item2 = dict_find(d2, hi->hi_key, -1); + if (item2 == NULL) + return FALSE; + if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic, recursive)) + return FALSE; + --todo; + } + } + return TRUE; +} + +/* + * Count the number of times item "needle" occurs in Dict "d". Case is ignored + * if "ic" is TRUE. + */ + long +dict_count(dict_T *d, typval_T *needle, int ic) +{ + int todo; + hashitem_T *hi; + long n = 0; + + if (d == NULL) + return 0; + + todo = (int)d->dv_hashtab.ht_used; + for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + --todo; + if (tv_equal(&HI2DI(hi)->di_tv, needle, ic, FALSE)) + ++n; + } + } + + return n; +} + +/* + * extend() a Dict. Append Dict argvars[1] to Dict argvars[0] and return the + * resulting Dict in "rettv". "is_new" is TRUE for extendnew(). + */ + void +dict_extend_func( + typval_T *argvars, + type_T *type, + char *func_name, + char_u *arg_errmsg, + int is_new, + typval_T *rettv) +{ + dict_T *d1, *d2; + char_u *action; + int i; + + d1 = argvars[0].vval.v_dict; + if (d1 == NULL) + { + emsg(_(e_cannot_extend_null_dict)); + return; + } + d2 = argvars[1].vval.v_dict; + if (d2 == NULL) + return; + + if (!is_new && value_check_lock(d1->dv_lock, arg_errmsg, TRUE)) + return; + + if (is_new) + { + d1 = dict_copy(d1, FALSE, TRUE, get_copyID()); + if (d1 == NULL) + return; + } + + // Check the third argument. + if (argvars[2].v_type != VAR_UNKNOWN) + { + static char *(av[]) = {"keep", "force", "error"}; + + action = tv_get_string_chk(&argvars[2]); + if (action == NULL) + return; + for (i = 0; i < 3; ++i) + if (STRCMP(action, av[i]) == 0) + break; + if (i == 3) + { + semsg(_(e_invalid_argument_str), action); + return; + } + } + else + action = (char_u *)"force"; + + if (type != NULL && check_typval_arg_type(type, &argvars[1], + func_name, 2) == FAIL) + return; + dict_extend(d1, d2, action, func_name); + + if (is_new) + { + rettv->v_type = VAR_DICT; + rettv->vval.v_dict = d1; + rettv->v_lock = FALSE; + } + else + copy_tv(&argvars[0], rettv); +} + +/* + * Implementation of map() and filter() for a Dict. Apply "expr" to every + * item in Dict "d" and return the result in "rettv". + */ + void +dict_filter_map( + dict_T *d, + filtermap_T filtermap, + type_T *argtype, + char *func_name, + char_u *arg_errmsg, + typval_T *expr, + typval_T *rettv) +{ + int prev_lock; + dict_T *d_ret = NULL; + hashtab_T *ht; + hashitem_T *hi; + dictitem_T *di; + int todo; + int rem; + typval_T newtv; + funccall_T *fc; + + if (filtermap == FILTERMAP_MAPNEW) + { + rettv->v_type = VAR_DICT; + rettv->vval.v_dict = NULL; + } + if (d == NULL + || (filtermap == FILTERMAP_FILTER + && value_check_lock(d->dv_lock, arg_errmsg, TRUE))) + return; + + prev_lock = d->dv_lock; + + if (filtermap == FILTERMAP_MAPNEW) + { + if (rettv_dict_alloc(rettv) == FAIL) + return; + d_ret = rettv->vval.v_dict; + } + + // Create one funccal_T for all eval_expr_typval() calls. + fc = eval_expr_get_funccal(expr, &newtv); + + if (filtermap != FILTERMAP_FILTER && d->dv_lock == 0) + d->dv_lock = VAR_LOCKED; + ht = &d->dv_hashtab; + hash_lock(ht); + todo = (int)ht->ht_used; + for (hi = ht->ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + int r; + + --todo; + di = HI2DI(hi); + if (filtermap == FILTERMAP_MAP + && (value_check_lock(di->di_tv.v_lock, + arg_errmsg, TRUE) + || var_check_ro(di->di_flags, + arg_errmsg, TRUE))) + break; + set_vim_var_string(VV_KEY, di->di_key, -1); + newtv.v_type = VAR_UNKNOWN; + r = filter_map_one(&di->di_tv, expr, filtermap, fc, &newtv, &rem); + clear_tv(get_vim_var_tv(VV_KEY)); + if (r == FAIL || did_emsg) + { + clear_tv(&newtv); + break; + } + if (filtermap == FILTERMAP_MAP) + { + if (argtype != NULL && check_typval_arg_type( + argtype->tt_member, &newtv, func_name, 0) == FAIL) + { + clear_tv(&newtv); + break; + } + // map(): replace the dict item value + clear_tv(&di->di_tv); + newtv.v_lock = 0; + di->di_tv = newtv; + } + else if (filtermap == FILTERMAP_MAPNEW) + { + // mapnew(): add the item value to the new dict + r = dict_add_tv(d_ret, (char *)di->di_key, &newtv); + clear_tv(&newtv); + if (r == FAIL) + break; + } + else if (filtermap == FILTERMAP_FILTER && rem) + { + // filter(false): remove the item from the dict + if (var_check_fixed(di->di_flags, arg_errmsg, TRUE) + || var_check_ro(di->di_flags, arg_errmsg, TRUE)) + break; + dictitem_remove(d, di, "filter"); + } + } + } + hash_unlock(ht); + d->dv_lock = prev_lock; + if (fc != NULL) + remove_funccal(); +} + +/* + * "remove({dict})" function + */ + void +dict_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg) +{ + dict_T *d; + char_u *key; + dictitem_T *di; + + if (argvars[2].v_type != VAR_UNKNOWN) + { + semsg(_(e_too_many_arguments_for_function_str), "remove()"); + return; + } + + d = argvars[0].vval.v_dict; + if (d == NULL || value_check_lock(d->dv_lock, arg_errmsg, TRUE)) + return; + + key = tv_get_string_chk(&argvars[1]); + if (key == NULL) + return; + + di = dict_find(d, key, -1); + if (di == NULL) + { + semsg(_(e_key_not_present_in_dictionary_str), key); + return; + } + + if (var_check_fixed(di->di_flags, arg_errmsg, TRUE) + || var_check_ro(di->di_flags, arg_errmsg, TRUE)) + return; + + *rettv = di->di_tv; + init_tv(&di->di_tv); + dictitem_remove(d, di, "remove()"); +} + +typedef enum { + DICT2LIST_KEYS, + DICT2LIST_VALUES, + DICT2LIST_ITEMS, +} dict2list_T; + +/* + * Turn a dict into a list. + */ + static void +dict2list(typval_T *argvars, typval_T *rettv, dict2list_T what) +{ + list_T *l2; + dictitem_T *di; + hashitem_T *hi; + listitem_T *li; + dict_T *d; + int todo; + + if (rettv_list_alloc(rettv) == FAIL) + return; + + if ((what == DICT2LIST_ITEMS + ? check_for_string_or_list_or_dict_arg(argvars, 0) + : check_for_dict_arg(argvars, 0)) == FAIL) + return; + + d = argvars[0].vval.v_dict; + if (d == NULL) + // empty dict behaves like an empty dict + return; + + todo = (int)d->dv_hashtab.ht_used; + for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + --todo; + di = HI2DI(hi); + + li = listitem_alloc(); + if (li == NULL) + break; + list_append(rettv->vval.v_list, li); + + if (what == DICT2LIST_KEYS) + { + // keys() + li->li_tv.v_type = VAR_STRING; + li->li_tv.v_lock = 0; + li->li_tv.vval.v_string = vim_strsave(di->di_key); + } + else if (what == DICT2LIST_VALUES) + { + // values() + copy_tv(&di->di_tv, &li->li_tv); + } + else + { + // items() + l2 = list_alloc(); + li->li_tv.v_type = VAR_LIST; + li->li_tv.v_lock = 0; + li->li_tv.vval.v_list = l2; + if (l2 == NULL) + break; + ++l2->lv_refcount; + + if (list_append_string(l2, di->di_key, -1) == FAIL + || list_append_tv(l2, &di->di_tv) == FAIL) + break; + } + } + } +} + +/* + * "items(dict)" function + */ + void +f_items(typval_T *argvars, typval_T *rettv) +{ + if (argvars[0].v_type == VAR_STRING) + string2items(argvars, rettv); + else if (argvars[0].v_type == VAR_LIST) + list2items(argvars, rettv); + else + dict2list(argvars, rettv, DICT2LIST_ITEMS); +} + +/* + * "keys()" function + */ + void +f_keys(typval_T *argvars, typval_T *rettv) +{ + dict2list(argvars, rettv, DICT2LIST_KEYS); +} + +/* + * "values(dict)" function + */ + void +f_values(typval_T *argvars, typval_T *rettv) +{ + dict2list(argvars, rettv, DICT2LIST_VALUES); +} + +/* + * Make each item in the dict readonly (not the value of the item). + */ + void +dict_set_items_ro(dict_T *di) +{ + int todo = (int)di->dv_hashtab.ht_used; + hashitem_T *hi; + + // Set readonly + for (hi = di->dv_hashtab.ht_array; todo > 0 ; ++hi) + { + if (HASHITEM_EMPTY(hi)) + continue; + --todo; + HI2DI(hi)->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX; + } +} + +/* + * "has_key()" function + */ + void +f_has_key(typval_T *argvars, typval_T *rettv) +{ + if (in_vim9script() + && (check_for_dict_arg(argvars, 0) == FAIL + || check_for_string_or_number_arg(argvars, 1) == FAIL)) + return; + + if (check_for_dict_arg(argvars, 0) == FAIL) + return; + + if (argvars[0].vval.v_dict == NULL) + return; + + rettv->vval.v_number = dict_has_key(argvars[0].vval.v_dict, + (char *)tv_get_string(&argvars[1])); +} + +#endif // defined(FEAT_EVAL) diff --git a/src/diff.c b/src/diff.c new file mode 100644 index 0000000..a155c5e --- /dev/null +++ b/src/diff.c @@ -0,0 +1,3439 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * diff.c: code for diff'ing two, three or four buffers. + * + * There are three ways to diff: + * - Shell out to an external diff program, using files. + * - Use the compiled-in xdiff library. + * - Let 'diffexpr' do the work, using files. + */ + +#include "vim.h" +#include "xdiff/xdiff.h" + +#if defined(FEAT_DIFF) || defined(PROTO) + +static int diff_busy = FALSE; // using diff structs, don't change them +static int diff_need_update = FALSE; // ex_diffupdate needs to be called + +// flags obtained from the 'diffopt' option +#define DIFF_FILLER 0x001 // display filler lines +#define DIFF_IBLANK 0x002 // ignore empty lines +#define DIFF_ICASE 0x004 // ignore case +#define DIFF_IWHITE 0x008 // ignore change in white space +#define DIFF_IWHITEALL 0x010 // ignore all white space changes +#define DIFF_IWHITEEOL 0x020 // ignore change in white space at EOL +#define DIFF_HORIZONTAL 0x040 // horizontal splits +#define DIFF_VERTICAL 0x080 // vertical splits +#define DIFF_HIDDEN_OFF 0x100 // diffoff when hidden +#define DIFF_INTERNAL 0x200 // use internal xdiff algorithm +#define DIFF_CLOSE_OFF 0x400 // diffoff when closing window +#define DIFF_FOLLOWWRAP 0x800 // follow the wrap option +#define ALL_WHITE_DIFF (DIFF_IWHITE | DIFF_IWHITEALL | DIFF_IWHITEEOL) +static int diff_flags = DIFF_INTERNAL | DIFF_FILLER | DIFF_CLOSE_OFF; + +static long diff_algorithm = 0; + +#define LBUFLEN 50 // length of line in diff file + +static int diff_a_works = MAYBE; // TRUE when "diff -a" works, FALSE when it + // doesn't work, MAYBE when not checked yet +#if defined(MSWIN) +static int diff_bin_works = MAYBE; // TRUE when "diff --binary" works, FALSE + // when it doesn't work, MAYBE when not + // checked yet +#endif + +// used for diff input +typedef struct { + char_u *din_fname; // used for external diff + mmfile_t din_mmfile; // used for internal diff +} diffin_T; + +// used for diff result +typedef struct { + char_u *dout_fname; // used for external diff + garray_T dout_ga; // used for internal diff +} diffout_T; + +// used for recording hunks from xdiff +typedef struct { + linenr_T lnum_orig; + long count_orig; + linenr_T lnum_new; + long count_new; +} diffhunk_T; + +// two diff inputs and one result +typedef struct { + diffin_T dio_orig; // original file input + diffin_T dio_new; // new file input + diffout_T dio_diff; // diff result + int dio_internal; // using internal diff +} diffio_T; + +static int diff_buf_idx(buf_T *buf); +static int diff_buf_idx_tp(buf_T *buf, tabpage_T *tp); +static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T line2, long amount, long amount_after); +static void diff_check_unchanged(tabpage_T *tp, diff_T *dp); +static int diff_check_sanity(tabpage_T *tp, diff_T *dp); +static int check_external_diff(diffio_T *diffio); +static int diff_file(diffio_T *diffio); +static int diff_equal_entry(diff_T *dp, int idx1, int idx2); +static int diff_cmp(char_u *s1, char_u *s2); +#ifdef FEAT_FOLDING +static void diff_fold_update(diff_T *dp, int skip_idx); +#endif +static void diff_read(int idx_orig, int idx_new, diffio_T *dio); +static void diff_copy_entry(diff_T *dprev, diff_T *dp, int idx_orig, int idx_new); +static diff_T *diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp); +static int parse_diff_ed(char_u *line, diffhunk_T *hunk); +static int parse_diff_unified(char_u *line, diffhunk_T *hunk); +static int xdiff_out(long start_a, long count_a, long start_b, long count_b, void *priv); + +#define FOR_ALL_DIFFBLOCKS_IN_TAB(tp, dp) \ + for ((dp) = (tp)->tp_first_diff; (dp) != NULL; (dp) = (dp)->df_next) + +/* + * Called when deleting or unloading a buffer: No longer make a diff with it. + */ + void +diff_buf_delete(buf_T *buf) +{ + int i; + tabpage_T *tp; + + FOR_ALL_TABPAGES(tp) + { + i = diff_buf_idx_tp(buf, tp); + if (i != DB_COUNT) + { + tp->tp_diffbuf[i] = NULL; + tp->tp_diff_invalid = TRUE; + if (tp == curtab) + { + // don't redraw right away, more might change or buffer state + // is invalid right now + need_diff_redraw = TRUE; + redraw_later(UPD_VALID); + } + } + } +} + +/* + * Check if the current buffer should be added to or removed from the list of + * diff buffers. + */ + void +diff_buf_adjust(win_T *win) +{ + win_T *wp; + int i; + + if (!win->w_p_diff) + { + // When there is no window showing a diff for this buffer, remove + // it from the diffs. + FOR_ALL_WINDOWS(wp) + if (wp->w_buffer == win->w_buffer && wp->w_p_diff) + break; + if (wp == NULL) + { + i = diff_buf_idx(win->w_buffer); + if (i != DB_COUNT) + { + curtab->tp_diffbuf[i] = NULL; + curtab->tp_diff_invalid = TRUE; + diff_redraw(TRUE); + } + } + } + else + diff_buf_add(win->w_buffer); +} + +/* + * Add a buffer to make diffs for. + * Call this when a new buffer is being edited in the current window where + * 'diff' is set. + * Marks the current buffer as being part of the diff and requiring updating. + * This must be done before any autocmd, because a command may use info + * about the screen contents. + */ + void +diff_buf_add(buf_T *buf) +{ + int i; + + if (diff_buf_idx(buf) != DB_COUNT) + return; // It's already there. + + for (i = 0; i < DB_COUNT; ++i) + if (curtab->tp_diffbuf[i] == NULL) + { + curtab->tp_diffbuf[i] = buf; + curtab->tp_diff_invalid = TRUE; + diff_redraw(TRUE); + return; + } + + semsg(_(e_cannot_diff_more_than_nr_buffers), DB_COUNT); +} + +/* + * Remove all buffers to make diffs for. + */ + static void +diff_buf_clear(void) +{ + int i; + + for (i = 0; i < DB_COUNT; ++i) + if (curtab->tp_diffbuf[i] != NULL) + { + curtab->tp_diffbuf[i] = NULL; + curtab->tp_diff_invalid = TRUE; + diff_redraw(TRUE); + } +} + +/* + * Find buffer "buf" in the list of diff buffers for the current tab page. + * Return its index or DB_COUNT if not found. + */ + static int +diff_buf_idx(buf_T *buf) +{ + int idx; + + for (idx = 0; idx < DB_COUNT; ++idx) + if (curtab->tp_diffbuf[idx] == buf) + break; + return idx; +} + +/* + * Find buffer "buf" in the list of diff buffers for tab page "tp". + * Return its index or DB_COUNT if not found. + */ + static int +diff_buf_idx_tp(buf_T *buf, tabpage_T *tp) +{ + int idx; + + for (idx = 0; idx < DB_COUNT; ++idx) + if (tp->tp_diffbuf[idx] == buf) + break; + return idx; +} + +/* + * Mark the diff info involving buffer "buf" as invalid, it will be updated + * when info is requested. + */ + void +diff_invalidate(buf_T *buf) +{ + tabpage_T *tp; + int i; + + FOR_ALL_TABPAGES(tp) + { + i = diff_buf_idx_tp(buf, tp); + if (i != DB_COUNT) + { + tp->tp_diff_invalid = TRUE; + if (tp == curtab) + diff_redraw(TRUE); + } + } +} + +/* + * Called by mark_adjust(): update line numbers in "curbuf". + */ + void +diff_mark_adjust( + linenr_T line1, + linenr_T line2, + long amount, + long amount_after) +{ + int idx; + tabpage_T *tp; + + // Handle all tab pages that use the current buffer in a diff. + FOR_ALL_TABPAGES(tp) + { + idx = diff_buf_idx_tp(curbuf, tp); + if (idx != DB_COUNT) + diff_mark_adjust_tp(tp, idx, line1, line2, amount, amount_after); + } +} + +/* + * Update line numbers in tab page "tp" for "curbuf" with index "idx". + * This attempts to update the changes as much as possible: + * When inserting/deleting lines outside of existing change blocks, create a + * new change block and update the line numbers in following blocks. + * When inserting/deleting lines in existing change blocks, update them. + */ + static void +diff_mark_adjust_tp( + tabpage_T *tp, + int idx, + linenr_T line1, + linenr_T line2, + long amount, + long amount_after) +{ + diff_T *dp; + diff_T *dprev; + diff_T *dnext; + int i; + int inserted, deleted; + int n, off; + linenr_T last; + linenr_T lnum_deleted = line1; // lnum of remaining deletion + int check_unchanged; + + if (diff_internal()) + { + // Will update diffs before redrawing. Set _invalid to update the + // diffs themselves, set _update to also update folds properly just + // before redrawing. + // Do update marks here, it is needed for :%diffput. + tp->tp_diff_invalid = TRUE; + tp->tp_diff_update = TRUE; + } + + if (line2 == MAXLNUM) + { + // mark_adjust(99, MAXLNUM, 9, 0): insert lines + inserted = amount; + deleted = 0; + } + else if (amount_after > 0) + { + // mark_adjust(99, 98, MAXLNUM, 9): a change that inserts lines + inserted = amount_after; + deleted = 0; + } + else + { + // mark_adjust(98, 99, MAXLNUM, -2): delete lines + inserted = 0; + deleted = -amount_after; + } + + dprev = NULL; + dp = tp->tp_first_diff; + for (;;) + { + // If the change is after the previous diff block and before the next + // diff block, thus not touching an existing change, create a new diff + // block. Don't do this when ex_diffgetput() is busy. + if ((dp == NULL || dp->df_lnum[idx] - 1 > line2 + || (line2 == MAXLNUM && dp->df_lnum[idx] > line1)) + && (dprev == NULL + || dprev->df_lnum[idx] + dprev->df_count[idx] < line1) + && !diff_busy) + { + dnext = diff_alloc_new(tp, dprev, dp); + if (dnext == NULL) + return; + + dnext->df_lnum[idx] = line1; + dnext->df_count[idx] = inserted; + for (i = 0; i < DB_COUNT; ++i) + if (tp->tp_diffbuf[i] != NULL && i != idx) + { + if (dprev == NULL) + dnext->df_lnum[i] = line1; + else + dnext->df_lnum[i] = line1 + + (dprev->df_lnum[i] + dprev->df_count[i]) + - (dprev->df_lnum[idx] + dprev->df_count[idx]); + dnext->df_count[i] = deleted; + } + } + + // if at end of the list, quit + if (dp == NULL) + break; + + /* + * Check for these situations: + * 1 2 3 + * 1 2 3 + * line1 2 3 4 5 + * 2 3 4 5 + * 2 3 4 5 + * line2 2 3 4 5 + * 3 5 6 + * 3 5 6 + */ + // compute last line of this change + last = dp->df_lnum[idx] + dp->df_count[idx] - 1; + + // 1. change completely above line1: nothing to do + if (last >= line1 - 1) + { + // 6. change below line2: only adjust for amount_after; also when + // "deleted" became zero when deleted all lines between two diffs + if (dp->df_lnum[idx] - (deleted + inserted != 0) > line2) + { + if (amount_after == 0) + break; // nothing left to change + dp->df_lnum[idx] += amount_after; + } + else + { + check_unchanged = FALSE; + + // 2. 3. 4. 5.: inserted/deleted lines touching this diff. + if (deleted > 0) + { + off = 0; + if (dp->df_lnum[idx] >= line1) + { + if (last <= line2) + { + // 4. delete all lines of diff + if (dp->df_next != NULL + && dp->df_next->df_lnum[idx] - 1 <= line2) + { + // delete continues in next diff, only do + // lines until that one + n = dp->df_next->df_lnum[idx] - lnum_deleted; + deleted -= n; + n -= dp->df_count[idx]; + lnum_deleted = dp->df_next->df_lnum[idx]; + } + else + n = deleted - dp->df_count[idx]; + dp->df_count[idx] = 0; + } + else + { + // 5. delete lines at or just before top of diff + off = dp->df_lnum[idx] - lnum_deleted; + n = off; + dp->df_count[idx] -= line2 - dp->df_lnum[idx] + 1; + check_unchanged = TRUE; + } + dp->df_lnum[idx] = line1; + } + else + { + if (last < line2) + { + // 2. delete at end of diff + dp->df_count[idx] -= last - lnum_deleted + 1; + if (dp->df_next != NULL + && dp->df_next->df_lnum[idx] - 1 <= line2) + { + // delete continues in next diff, only do + // lines until that one + n = dp->df_next->df_lnum[idx] - 1 - last; + deleted -= dp->df_next->df_lnum[idx] + - lnum_deleted; + lnum_deleted = dp->df_next->df_lnum[idx]; + } + else + n = line2 - last; + check_unchanged = TRUE; + } + else + { + // 3. delete lines inside the diff + n = 0; + dp->df_count[idx] -= deleted; + } + } + + for (i = 0; i < DB_COUNT; ++i) + if (tp->tp_diffbuf[i] != NULL && i != idx) + { + if (dp->df_lnum[i] > off) + dp->df_lnum[i] -= off; + else + dp->df_lnum[i] = 1; + dp->df_count[i] += n; + } + } + else + { + if (dp->df_lnum[idx] <= line1) + { + // inserted lines somewhere in this diff + dp->df_count[idx] += inserted; + check_unchanged = TRUE; + } + else + // inserted lines somewhere above this diff + dp->df_lnum[idx] += inserted; + } + + if (check_unchanged) + // Check if inserted lines are equal, may reduce the + // size of the diff. TODO: also check for equal lines + // in the middle and perhaps split the block. + diff_check_unchanged(tp, dp); + } + } + + // check if this block touches the previous one, may merge them. + if (dprev != NULL && dprev->df_lnum[idx] + dprev->df_count[idx] + == dp->df_lnum[idx]) + { + for (i = 0; i < DB_COUNT; ++i) + if (tp->tp_diffbuf[i] != NULL) + dprev->df_count[i] += dp->df_count[i]; + dprev->df_next = dp->df_next; + vim_free(dp); + dp = dprev->df_next; + } + else + { + // Advance to next entry. + dprev = dp; + dp = dp->df_next; + } + } + + dprev = NULL; + dp = tp->tp_first_diff; + while (dp != NULL) + { + // All counts are zero, remove this entry. + for (i = 0; i < DB_COUNT; ++i) + if (tp->tp_diffbuf[i] != NULL && dp->df_count[i] != 0) + break; + if (i == DB_COUNT) + { + dnext = dp->df_next; + vim_free(dp); + dp = dnext; + if (dprev == NULL) + tp->tp_first_diff = dnext; + else + dprev->df_next = dnext; + } + else + { + // Advance to next entry. + dprev = dp; + dp = dp->df_next; + } + + } + + if (tp == curtab) + { + // Don't redraw right away, this updates the diffs, which can be slow. + need_diff_redraw = TRUE; + + // Need to recompute the scroll binding, may remove or add filler + // lines (e.g., when adding lines above w_topline). But it's slow when + // making many changes, postpone until redrawing. + diff_need_scrollbind = TRUE; + } +} + +/* + * Allocate a new diff block and link it between "dprev" and "dp". + */ + static diff_T * +diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp) +{ + diff_T *dnew; + + dnew = ALLOC_ONE(diff_T); + if (dnew == NULL) + return NULL; + + dnew->df_next = dp; + if (dprev == NULL) + tp->tp_first_diff = dnew; + else + dprev->df_next = dnew; + return dnew; +} + +/* + * Check if the diff block "dp" can be made smaller for lines at the start and + * end that are equal. Called after inserting lines. + * This may result in a change where all buffers have zero lines, the caller + * must take care of removing it. + */ + static void +diff_check_unchanged(tabpage_T *tp, diff_T *dp) +{ + int i_org; + int i_new; + int off_org, off_new; + char_u *line_org; + int dir = FORWARD; + + // Find the first buffers, use it as the original, compare the other + // buffer lines against this one. + for (i_org = 0; i_org < DB_COUNT; ++i_org) + if (tp->tp_diffbuf[i_org] != NULL) + break; + if (i_org == DB_COUNT) // safety check + return; + + if (diff_check_sanity(tp, dp) == FAIL) + return; + + // First check lines at the top, then at the bottom. + off_org = 0; + off_new = 0; + for (;;) + { + // Repeat until a line is found which is different or the number of + // lines has become zero. + while (dp->df_count[i_org] > 0) + { + // Copy the line, the next ml_get() will invalidate it. + if (dir == BACKWARD) + off_org = dp->df_count[i_org] - 1; + line_org = vim_strsave(ml_get_buf(tp->tp_diffbuf[i_org], + dp->df_lnum[i_org] + off_org, FALSE)); + if (line_org == NULL) + return; + for (i_new = i_org + 1; i_new < DB_COUNT; ++i_new) + { + if (tp->tp_diffbuf[i_new] == NULL) + continue; + if (dir == BACKWARD) + off_new = dp->df_count[i_new] - 1; + // if other buffer doesn't have this line, it was inserted + if (off_new < 0 || off_new >= dp->df_count[i_new]) + break; + if (diff_cmp(line_org, ml_get_buf(tp->tp_diffbuf[i_new], + dp->df_lnum[i_new] + off_new, FALSE)) != 0) + break; + } + vim_free(line_org); + + // Stop when a line isn't equal in all diff buffers. + if (i_new != DB_COUNT) + break; + + // Line matched in all buffers, remove it from the diff. + for (i_new = i_org; i_new < DB_COUNT; ++i_new) + if (tp->tp_diffbuf[i_new] != NULL) + { + if (dir == FORWARD) + ++dp->df_lnum[i_new]; + --dp->df_count[i_new]; + } + } + if (dir == BACKWARD) + break; + dir = BACKWARD; + } +} + +/* + * Check if a diff block doesn't contain invalid line numbers. + * This can happen when the diff program returns invalid results. + */ + static int +diff_check_sanity(tabpage_T *tp, diff_T *dp) +{ + int i; + + for (i = 0; i < DB_COUNT; ++i) + if (tp->tp_diffbuf[i] != NULL) + if (dp->df_lnum[i] + dp->df_count[i] - 1 + > tp->tp_diffbuf[i]->b_ml.ml_line_count) + return FAIL; + return OK; +} + +/* + * Mark all diff buffers in the current tab page for redraw. + */ + void +diff_redraw( + int dofold) // also recompute the folds +{ + win_T *wp; + win_T *wp_other = NULL; + int used_max_fill_other = FALSE; + int used_max_fill_curwin = FALSE; + int n; + + need_diff_redraw = FALSE; + FOR_ALL_WINDOWS(wp) + { + // when closing windows or wiping buffers skip invalid window + if (!wp->w_p_diff || !buf_valid(wp->w_buffer)) + continue; + + redraw_win_later(wp, UPD_SOME_VALID); + if (wp != curwin) + wp_other = wp; +#ifdef FEAT_FOLDING + if (dofold && foldmethodIsDiff(wp)) + foldUpdateAll(wp); +#endif + // A change may have made filler lines invalid, need to take care of + // that for other windows. + n = diff_check(wp, wp->w_topline); + if ((wp != curwin && wp->w_topfill > 0) || n > 0) + { + if (wp->w_topfill > n) + wp->w_topfill = (n < 0 ? 0 : n); + else if (n > 0 && n > wp->w_topfill) + { + wp->w_topfill = n; + if (wp == curwin) + used_max_fill_curwin = TRUE; + else if (wp_other != NULL) + used_max_fill_other = TRUE; + } + check_topfill(wp, FALSE); + } + } + + if (wp_other != NULL && curwin->w_p_scb) + { + if (used_max_fill_curwin) + // The current window was set to use the maximum number of filler + // lines, may need to reduce them. + diff_set_topline(wp_other, curwin); + else if (used_max_fill_other) + // The other window was set to use the maximum number of filler + // lines, may need to reduce them. + diff_set_topline(curwin, wp_other); + } +} + + static void +clear_diffin(diffin_T *din) +{ + if (din->din_fname == NULL) + { + vim_free(din->din_mmfile.ptr); + din->din_mmfile.ptr = NULL; + } + else + mch_remove(din->din_fname); +} + + static void +clear_diffout(diffout_T *dout) +{ + if (dout->dout_fname == NULL) + ga_clear_strings(&dout->dout_ga); + else + mch_remove(dout->dout_fname); +} + +/* + * Write buffer "buf" to a memory buffer. + * Return FAIL for failure. + */ + static int +diff_write_buffer(buf_T *buf, diffin_T *din) +{ + linenr_T lnum; + char_u *s; + long len = 0; + char_u *ptr; + + // xdiff requires one big block of memory with all the text. + for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum) + len += (long)STRLEN(ml_get_buf(buf, lnum, FALSE)) + 1; + ptr = alloc(len); + if (ptr == NULL) + { + // Allocating memory failed. This can happen, because we try to read + // the whole buffer text into memory. Set the failed flag, the diff + // will be retried with external diff. The flag is never reset. + buf->b_diff_failed = TRUE; + if (p_verbose > 0) + { + verbose_enter(); + smsg(_("Not enough memory to use internal diff for buffer \"%s\""), + buf->b_fname); + verbose_leave(); + } + return FAIL; + } + din->din_mmfile.ptr = (char *)ptr; + din->din_mmfile.size = len; + + len = 0; + for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum) + { + for (s = ml_get_buf(buf, lnum, FALSE); *s != NUL; ) + { + if (diff_flags & DIFF_ICASE) + { + int c; + int orig_len; + char_u cbuf[MB_MAXBYTES + 1]; + + if (*s == NL) + c = NUL; + else + { + // xdiff doesn't support ignoring case, fold-case the text. + c = PTR2CHAR(s); + c = MB_CASEFOLD(c); + } + orig_len = mb_ptr2len(s); + if (mb_char2bytes(c, cbuf) != orig_len) + // TODO: handle byte length difference + mch_memmove(ptr + len, s, orig_len); + else + mch_memmove(ptr + len, cbuf, orig_len); + + s += orig_len; + len += orig_len; + } + else + { + ptr[len++] = *s == NL ? NUL : *s; + s++; + } + } + ptr[len++] = NL; + } + return OK; +} + +/* + * Write buffer "buf" to file or memory buffer. + * Return FAIL for failure. + */ + static int +diff_write(buf_T *buf, diffin_T *din) +{ + int r; + char_u *save_ff; + int save_cmod_flags; + + if (din->din_fname == NULL) + return diff_write_buffer(buf, din); + + // Always use 'fileformat' set to "unix". + save_ff = buf->b_p_ff; + buf->b_p_ff = vim_strsave((char_u *)FF_UNIX); + save_cmod_flags = cmdmod.cmod_flags; + // Writing the buffer is an implementation detail of performing the diff, + // so it shouldn't update the '[ and '] marks. + cmdmod.cmod_flags |= CMOD_LOCKMARKS; + r = buf_write(buf, din->din_fname, NULL, + (linenr_T)1, buf->b_ml.ml_line_count, + NULL, FALSE, FALSE, FALSE, TRUE); + cmdmod.cmod_flags = save_cmod_flags; + free_string_option(buf->b_p_ff); + buf->b_p_ff = save_ff; + return r; +} + +/* + * Update the diffs for all buffers involved. + */ + static void +diff_try_update( + diffio_T *dio, + int idx_orig, + exarg_T *eap) // "eap" can be NULL +{ + buf_T *buf; + int idx_new; + + if (dio->dio_internal) + { + ga_init2(&dio->dio_diff.dout_ga, sizeof(char *), 1000); + } + else + { + // We need three temp file names. + dio->dio_orig.din_fname = vim_tempname('o', TRUE); + dio->dio_new.din_fname = vim_tempname('n', TRUE); + dio->dio_diff.dout_fname = vim_tempname('d', TRUE); + if (dio->dio_orig.din_fname == NULL + || dio->dio_new.din_fname == NULL + || dio->dio_diff.dout_fname == NULL) + goto theend; + } + + // Check external diff is actually working. + if (!dio->dio_internal && check_external_diff(dio) == FAIL) + goto theend; + + // :diffupdate! + if (eap != NULL && eap->forceit) + for (idx_new = idx_orig; idx_new < DB_COUNT; ++idx_new) + { + buf = curtab->tp_diffbuf[idx_new]; + if (buf_valid(buf)) + buf_check_timestamp(buf, FALSE); + } + + // Write the first buffer to a tempfile or mmfile_t. + buf = curtab->tp_diffbuf[idx_orig]; + if (diff_write(buf, &dio->dio_orig) == FAIL) + goto theend; + + // Make a difference between the first buffer and every other. + for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new) + { + buf = curtab->tp_diffbuf[idx_new]; + if (buf == NULL || buf->b_ml.ml_mfp == NULL) + continue; // skip buffer that isn't loaded + + // Write the other buffer and diff with the first one. + if (diff_write(buf, &dio->dio_new) == FAIL) + continue; + if (diff_file(dio) == FAIL) + continue; + + // Read the diff output and add each entry to the diff list. + diff_read(idx_orig, idx_new, dio); + + clear_diffin(&dio->dio_new); + clear_diffout(&dio->dio_diff); + } + clear_diffin(&dio->dio_orig); + +theend: + vim_free(dio->dio_orig.din_fname); + vim_free(dio->dio_new.din_fname); + vim_free(dio->dio_diff.dout_fname); +} + +/* + * Return TRUE if the options are set to use the internal diff library. + * Note that if the internal diff failed for one of the buffers, the external + * diff will be used anyway. + */ + int +diff_internal(void) +{ + return (diff_flags & DIFF_INTERNAL) != 0 +#ifdef FEAT_EVAL + && *p_dex == NUL +#endif + ; +} + +/* + * Return TRUE if the internal diff failed for one of the diff buffers. + */ + static int +diff_internal_failed(void) +{ + int idx; + + // Only need to do something when there is another buffer. + for (idx = 0; idx < DB_COUNT; ++idx) + if (curtab->tp_diffbuf[idx] != NULL + && curtab->tp_diffbuf[idx]->b_diff_failed) + return TRUE; + return FALSE; +} + +/* + * Completely update the diffs for the buffers involved. + * When using the external "diff" command the buffers are written to a file, + * also for unmodified buffers (the file could have been produced by + * autocommands, e.g. the netrw plugin). + */ + void +ex_diffupdate(exarg_T *eap) // "eap" can be NULL +{ + int idx_orig; + int idx_new; + diffio_T diffio; + int had_diffs = curtab->tp_first_diff != NULL; + + if (diff_busy) + { + diff_need_update = TRUE; + return; + } + + // Delete all diffblocks. + diff_clear(curtab); + curtab->tp_diff_invalid = FALSE; + + // Use the first buffer as the original text. + for (idx_orig = 0; idx_orig < DB_COUNT; ++idx_orig) + if (curtab->tp_diffbuf[idx_orig] != NULL) + break; + if (idx_orig == DB_COUNT) + goto theend; + + // Only need to do something when there is another buffer. + for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new) + if (curtab->tp_diffbuf[idx_new] != NULL) + break; + if (idx_new == DB_COUNT) + goto theend; + + // Only use the internal method if it did not fail for one of the buffers. + CLEAR_FIELD(diffio); + diffio.dio_internal = diff_internal() && !diff_internal_failed(); + + diff_try_update(&diffio, idx_orig, eap); + if (diffio.dio_internal && diff_internal_failed()) + { + // Internal diff failed, use external diff instead. + CLEAR_FIELD(diffio); + diff_try_update(&diffio, idx_orig, eap); + } + + // force updating cursor position on screen + curwin->w_valid_cursor.lnum = 0; + +theend: + // A redraw is needed if there were diffs and they were cleared, or there + // are diffs now, which means they got updated. + if (had_diffs || curtab->tp_first_diff != NULL) + { + diff_redraw(TRUE); + apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, FALSE, curbuf); + } +} + +/* + * Do a quick test if "diff" really works. Otherwise it looks like there + * are no differences. Can't use the return value, it's non-zero when + * there are differences. + */ + static int +check_external_diff(diffio_T *diffio) +{ + FILE *fd; + int ok; + int io_error = FALSE; + + // May try twice, first with "-a" and then without. + for (;;) + { + ok = FALSE; + fd = mch_fopen((char *)diffio->dio_orig.din_fname, "w"); + if (fd == NULL) + io_error = TRUE; + else + { + if (fwrite("line1\n", (size_t)6, (size_t)1, fd) != 1) + io_error = TRUE; + fclose(fd); + fd = mch_fopen((char *)diffio->dio_new.din_fname, "w"); + if (fd == NULL) + io_error = TRUE; + else + { + if (fwrite("line2\n", (size_t)6, (size_t)1, fd) != 1) + io_error = TRUE; + fclose(fd); + fd = NULL; + if (diff_file(diffio) == OK) + fd = mch_fopen((char *)diffio->dio_diff.dout_fname, "r"); + if (fd == NULL) + io_error = TRUE; + else + { + char_u linebuf[LBUFLEN]; + + for (;;) + { + // For normal diff there must be a line that contains + // "1c1". For unified diff "@@ -1 +1 @@". + if (vim_fgets(linebuf, LBUFLEN, fd)) + break; + if (STRNCMP(linebuf, "1c1", 3) == 0 + || STRNCMP(linebuf, "@@ -1 +1 @@", 11) == 0) + ok = TRUE; + } + fclose(fd); + } + mch_remove(diffio->dio_diff.dout_fname); + mch_remove(diffio->dio_new.din_fname); + } + mch_remove(diffio->dio_orig.din_fname); + } + +#ifdef FEAT_EVAL + // When using 'diffexpr' break here. + if (*p_dex != NUL) + break; +#endif + +#if defined(MSWIN) + // If the "-a" argument works, also check if "--binary" works. + if (ok && diff_a_works == MAYBE && diff_bin_works == MAYBE) + { + diff_a_works = TRUE; + diff_bin_works = TRUE; + continue; + } + if (!ok && diff_a_works == TRUE && diff_bin_works == TRUE) + { + // Tried --binary, but it failed. "-a" works though. + diff_bin_works = FALSE; + ok = TRUE; + } +#endif + + // If we checked if "-a" works already, break here. + if (diff_a_works != MAYBE) + break; + diff_a_works = ok; + + // If "-a" works break here, otherwise retry without "-a". + if (ok) + break; + } + if (!ok) + { + if (io_error) + emsg(_(e_cannot_read_or_write_temp_files)); + emsg(_(e_cannot_create_diffs)); + diff_a_works = MAYBE; +#if defined(MSWIN) + diff_bin_works = MAYBE; +#endif + return FAIL; + } + return OK; +} + +/* + * Invoke the xdiff function. + */ + static int +diff_file_internal(diffio_T *diffio) +{ + xpparam_t param; + xdemitconf_t emit_cfg; + xdemitcb_t emit_cb; + + CLEAR_FIELD(param); + CLEAR_FIELD(emit_cfg); + CLEAR_FIELD(emit_cb); + + param.flags = diff_algorithm; + + if (diff_flags & DIFF_IWHITE) + param.flags |= XDF_IGNORE_WHITESPACE_CHANGE; + if (diff_flags & DIFF_IWHITEALL) + param.flags |= XDF_IGNORE_WHITESPACE; + if (diff_flags & DIFF_IWHITEEOL) + param.flags |= XDF_IGNORE_WHITESPACE_AT_EOL; + if (diff_flags & DIFF_IBLANK) + param.flags |= XDF_IGNORE_BLANK_LINES; + + emit_cfg.ctxlen = 0; // don't need any diff_context here + emit_cb.priv = &diffio->dio_diff; + emit_cfg.hunk_func = xdiff_out; + if (xdl_diff(&diffio->dio_orig.din_mmfile, + &diffio->dio_new.din_mmfile, + ¶m, &emit_cfg, &emit_cb) < 0) + { + emsg(_(e_problem_creating_internal_diff)); + return FAIL; + } + return OK; +} + +/* + * Make a diff between files "tmp_orig" and "tmp_new", results in "tmp_diff". + * return OK or FAIL; + */ + static int +diff_file(diffio_T *dio) +{ + char_u *cmd; + size_t len; + char_u *tmp_orig = dio->dio_orig.din_fname; + char_u *tmp_new = dio->dio_new.din_fname; + char_u *tmp_diff = dio->dio_diff.dout_fname; + +#ifdef FEAT_EVAL + if (*p_dex != NUL) + { + // Use 'diffexpr' to generate the diff file. + eval_diff(tmp_orig, tmp_new, tmp_diff); + return OK; + } + else +#endif + // Use xdiff for generating the diff. + if (dio->dio_internal) + return diff_file_internal(dio); + + len = STRLEN(tmp_orig) + STRLEN(tmp_new) + + STRLEN(tmp_diff) + STRLEN(p_srr) + 27; + cmd = alloc(len); + if (cmd == NULL) + return FAIL; + + // We don't want $DIFF_OPTIONS to get in the way. + if (getenv("DIFF_OPTIONS")) + vim_setenv((char_u *)"DIFF_OPTIONS", (char_u *)""); + + // Build the diff command and execute it. Always use -a, binary + // differences are of no use. Ignore errors, diff returns + // non-zero when differences have been found. + vim_snprintf((char *)cmd, len, "diff %s%s%s%s%s%s%s%s %s", + diff_a_works == FALSE ? "" : "-a ", +#if defined(MSWIN) + diff_bin_works == TRUE ? "--binary " : "", +#else + "", +#endif + (diff_flags & DIFF_IWHITE) ? "-b " : "", + (diff_flags & DIFF_IWHITEALL) ? "-w " : "", + (diff_flags & DIFF_IWHITEEOL) ? "-Z " : "", + (diff_flags & DIFF_IBLANK) ? "-B " : "", + (diff_flags & DIFF_ICASE) ? "-i " : "", + tmp_orig, tmp_new); + append_redir(cmd, (int)len, p_srr, tmp_diff); + block_autocmds(); // avoid ShellCmdPost stuff + (void)call_shell(cmd, SHELL_FILTER|SHELL_SILENT|SHELL_DOOUT); + unblock_autocmds(); + vim_free(cmd); + return OK; +} + +/* + * Create a new version of a file from the current buffer and a diff file. + * The buffer is written to a file, also for unmodified buffers (the file + * could have been produced by autocommands, e.g. the netrw plugin). + */ + void +ex_diffpatch(exarg_T *eap) +{ + char_u *tmp_orig; // name of original temp file + char_u *tmp_new; // name of patched temp file + char_u *buf = NULL; + size_t buflen; + win_T *old_curwin = curwin; + char_u *newname = NULL; // name of patched file buffer +#ifdef UNIX + char_u dirbuf[MAXPATHL]; + char_u *fullname = NULL; +#endif +#ifdef FEAT_BROWSE + char_u *browseFile = NULL; + int save_cmod_flags = cmdmod.cmod_flags; +#endif + stat_T st; + char_u *esc_name = NULL; + +#ifdef FEAT_BROWSE + if (cmdmod.cmod_flags & CMOD_BROWSE) + { + browseFile = do_browse(0, (char_u *)_("Patch file"), + eap->arg, NULL, NULL, + (char_u *)_(BROWSE_FILTER_ALL_FILES), NULL); + if (browseFile == NULL) + return; // operation cancelled + eap->arg = browseFile; + cmdmod.cmod_flags &= ~CMOD_BROWSE; // don't let do_ecmd() browse again + } +#endif + + // We need two temp file names. + tmp_orig = vim_tempname('o', FALSE); + tmp_new = vim_tempname('n', FALSE); + if (tmp_orig == NULL || tmp_new == NULL) + goto theend; + + // Write the current buffer to "tmp_orig". + if (buf_write(curbuf, tmp_orig, NULL, + (linenr_T)1, curbuf->b_ml.ml_line_count, + NULL, FALSE, FALSE, FALSE, TRUE) == FAIL) + goto theend; + +#ifdef UNIX + // Get the absolute path of the patchfile, changing directory below. + fullname = FullName_save(eap->arg, FALSE); +#endif + esc_name = vim_strsave_shellescape( +# ifdef UNIX + fullname != NULL ? fullname : +# endif + eap->arg, TRUE, TRUE); + if (esc_name == NULL) + goto theend; + buflen = STRLEN(tmp_orig) + STRLEN(esc_name) + STRLEN(tmp_new) + 16; + buf = alloc(buflen); + if (buf == NULL) + goto theend; + +#ifdef UNIX + // Temporarily chdir to /tmp, to avoid patching files in the current + // directory when the patch file contains more than one patch. When we + // have our own temp dir use that instead, it will be cleaned up when we + // exit (any .rej files created). Don't change directory if we can't + // return to the current. + if (mch_dirname(dirbuf, MAXPATHL) != OK || mch_chdir((char *)dirbuf) != 0) + dirbuf[0] = NUL; + else + { +# ifdef TEMPDIRNAMES + if (vim_tempdir != NULL) + vim_ignored = mch_chdir((char *)vim_tempdir); + else +# endif + vim_ignored = mch_chdir("/tmp"); + shorten_fnames(TRUE); + } +#endif + +#ifdef FEAT_EVAL + if (*p_pex != NUL) + // Use 'patchexpr' to generate the new file. + eval_patch(tmp_orig, +# ifdef UNIX + fullname != NULL ? fullname : +# endif + eap->arg, tmp_new); + else +#endif + { + // Build the patch command and execute it. Ignore errors. Switch to + // cooked mode to allow the user to respond to prompts. + vim_snprintf((char *)buf, buflen, "patch -o %s %s < %s", + tmp_new, tmp_orig, esc_name); + block_autocmds(); // Avoid ShellCmdPost stuff + (void)call_shell(buf, SHELL_FILTER | SHELL_COOKED); + unblock_autocmds(); + } + +#ifdef UNIX + if (dirbuf[0] != NUL) + { + if (mch_chdir((char *)dirbuf) != 0) + emsg(_(e_cannot_go_back_to_previous_directory)); + shorten_fnames(TRUE); + } +#endif + + // patch probably has written over the screen + redraw_later(UPD_CLEAR); + + // Delete any .orig or .rej file created. + STRCPY(buf, tmp_new); + STRCAT(buf, ".orig"); + mch_remove(buf); + STRCPY(buf, tmp_new); + STRCAT(buf, ".rej"); + mch_remove(buf); + + // Only continue if the output file was created. + if (mch_stat((char *)tmp_new, &st) < 0 || st.st_size == 0) + emsg(_(e_cannot_read_patch_output)); + else + { + if (curbuf->b_fname != NULL) + { + newname = vim_strnsave(curbuf->b_fname, + STRLEN(curbuf->b_fname) + 4); + if (newname != NULL) + STRCAT(newname, ".new"); + } + +#ifdef FEAT_GUI + need_mouse_correct = TRUE; +#endif + // don't use a new tab page, each tab page has its own diffs + cmdmod.cmod_tab = 0; + + if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) != FAIL) + { + // Pretend it was a ":split fname" command + eap->cmdidx = CMD_split; + eap->arg = tmp_new; + do_exedit(eap, old_curwin); + + // check that split worked and editing tmp_new + if (curwin != old_curwin && win_valid(old_curwin)) + { + // Set 'diff', 'scrollbind' on and 'wrap' off. + diff_win_options(curwin, TRUE); + diff_win_options(old_curwin, TRUE); + + if (newname != NULL) + { + // do a ":file filename.new" on the patched buffer + eap->arg = newname; + ex_file(eap); + + // Do filetype detection with the new name. + if (au_has_group((char_u *)"filetypedetect")) + do_cmdline_cmd((char_u *)":doau filetypedetect BufRead"); + } + } + } + } + +theend: + if (tmp_orig != NULL) + mch_remove(tmp_orig); + vim_free(tmp_orig); + if (tmp_new != NULL) + mch_remove(tmp_new); + vim_free(tmp_new); + vim_free(newname); + vim_free(buf); +#ifdef UNIX + vim_free(fullname); +#endif + vim_free(esc_name); +#ifdef FEAT_BROWSE + vim_free(browseFile); + cmdmod.cmod_flags = save_cmod_flags; +#endif +} + +/* + * Split the window and edit another file, setting options to show the diffs. + */ + void +ex_diffsplit(exarg_T *eap) +{ + win_T *old_curwin = curwin; + bufref_T old_curbuf; + + set_bufref(&old_curbuf, curbuf); +#ifdef FEAT_GUI + need_mouse_correct = TRUE; +#endif + // Need to compute w_fraction when no redraw happened yet. + validate_cursor(); + set_fraction(curwin); + + // don't use a new tab page, each tab page has its own diffs + cmdmod.cmod_tab = 0; + + if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) == FAIL) + return; + + // Pretend it was a ":split fname" command + eap->cmdidx = CMD_split; + curwin->w_p_diff = TRUE; + do_exedit(eap, old_curwin); + + if (curwin == old_curwin) // split didn't work + return; + + // Set 'diff', 'scrollbind' on and 'wrap' off. + diff_win_options(curwin, TRUE); + if (win_valid(old_curwin)) + { + diff_win_options(old_curwin, TRUE); + + if (bufref_valid(&old_curbuf)) + // Move the cursor position to that of the old window. + curwin->w_cursor.lnum = diff_get_corresponding_line( + old_curbuf.br_buf, old_curwin->w_cursor.lnum); + } + // Now that lines are folded scroll to show the cursor at the same + // relative position. + scroll_to_fraction(curwin, curwin->w_height); +} + +/* + * Set options to show diffs for the current window. + */ + void +ex_diffthis(exarg_T *eap UNUSED) +{ + // Set 'diff', 'scrollbind' on and 'wrap' off. + diff_win_options(curwin, TRUE); +} + + static void +set_diff_option(win_T *wp, int value) +{ + win_T *old_curwin = curwin; + + curwin = wp; + curbuf = curwin->w_buffer; + ++curbuf_lock; + set_option_value_give_err((char_u *)"diff", (long)value, NULL, OPT_LOCAL); + --curbuf_lock; + curwin = old_curwin; + curbuf = curwin->w_buffer; +} + +/* + * Set options in window "wp" for diff mode. + */ + void +diff_win_options( + win_T *wp, + int addbuf) // Add buffer to diff. +{ +# ifdef FEAT_FOLDING + win_T *old_curwin = curwin; + + // close the manually opened folds + curwin = wp; + newFoldLevel(); + curwin = old_curwin; +# endif + + // Use 'scrollbind' and 'cursorbind' when available + if (!wp->w_p_diff) + wp->w_p_scb_save = wp->w_p_scb; + wp->w_p_scb = TRUE; + if (!wp->w_p_diff) + wp->w_p_crb_save = wp->w_p_crb; + wp->w_p_crb = TRUE; + if (!(diff_flags & DIFF_FOLLOWWRAP)) + { + if (!wp->w_p_diff) + wp->w_p_wrap_save = wp->w_p_wrap; + wp->w_p_wrap = FALSE; + } +# ifdef FEAT_FOLDING + if (!wp->w_p_diff) + { + if (wp->w_p_diff_saved) + free_string_option(wp->w_p_fdm_save); + wp->w_p_fdm_save = vim_strsave(wp->w_p_fdm); + } + set_string_option_direct_in_win(wp, (char_u *)"fdm", -1, (char_u *)"diff", + OPT_LOCAL|OPT_FREE, 0); + if (!wp->w_p_diff) + { + wp->w_p_fdc_save = wp->w_p_fdc; + wp->w_p_fen_save = wp->w_p_fen; + wp->w_p_fdl_save = wp->w_p_fdl; + } + wp->w_p_fdc = diff_foldcolumn; + wp->w_p_fen = TRUE; + wp->w_p_fdl = 0; + foldUpdateAll(wp); + // make sure topline is not halfway a fold + changed_window_setting_win(wp); +# endif + if (vim_strchr(p_sbo, 'h') == NULL) + do_cmdline_cmd((char_u *)"set sbo+=hor"); + // Save the current values, to be restored in ex_diffoff(). + wp->w_p_diff_saved = TRUE; + + set_diff_option(wp, TRUE); + + if (addbuf) + diff_buf_add(wp->w_buffer); + redraw_win_later(wp, UPD_NOT_VALID); +} + +/* + * Set options not to show diffs. For the current window or all windows. + * Only in the current tab page. + */ + void +ex_diffoff(exarg_T *eap) +{ + win_T *wp; + int diffwin = FALSE; + + FOR_ALL_WINDOWS(wp) + { + if (eap->forceit ? wp->w_p_diff : wp == curwin) + { + // Set 'diff' off. If option values were saved in + // diff_win_options(), restore the ones whose settings seem to have + // been left over from diff mode. + set_diff_option(wp, FALSE); + + if (wp->w_p_diff_saved) + { + + if (wp->w_p_scb) + wp->w_p_scb = wp->w_p_scb_save; + if (wp->w_p_crb) + wp->w_p_crb = wp->w_p_crb_save; + if (!(diff_flags & DIFF_FOLLOWWRAP)) + { + if (!wp->w_p_wrap) + wp->w_p_wrap = wp->w_p_wrap_save; + } +#ifdef FEAT_FOLDING + free_string_option(wp->w_p_fdm); + wp->w_p_fdm = vim_strsave( + *wp->w_p_fdm_save ? wp->w_p_fdm_save : (char_u*)"manual"); + + if (wp->w_p_fdc == diff_foldcolumn) + wp->w_p_fdc = wp->w_p_fdc_save; + if (wp->w_p_fdl == 0) + wp->w_p_fdl = wp->w_p_fdl_save; + + // Only restore 'foldenable' when 'foldmethod' is not + // "manual", otherwise we continue to show the diff folds. + if (wp->w_p_fen) + wp->w_p_fen = foldmethodIsManual(wp) ? FALSE + : wp->w_p_fen_save; + + foldUpdateAll(wp); +#endif + } + // remove filler lines + wp->w_topfill = 0; + + // make sure topline is not halfway a fold and cursor is + // invalidated + changed_window_setting_win(wp); + + // Note: 'sbo' is not restored, it's a global option. + diff_buf_adjust(wp); + } + diffwin |= wp->w_p_diff; + } + + // Also remove hidden buffers from the list. + if (eap->forceit) + diff_buf_clear(); + + if (!diffwin) + { + diff_need_update = FALSE; + curtab->tp_diff_invalid = FALSE; + curtab->tp_diff_update = FALSE; + diff_clear(curtab); + } + + // Remove "hor" from 'scrollopt' if there are no diff windows left. + if (!diffwin && vim_strchr(p_sbo, 'h') != NULL) + do_cmdline_cmd((char_u *)"set sbo-=hor"); +} + +/* + * Read the diff output and add each entry to the diff list. + */ + static void +diff_read( + int idx_orig, // idx of original file + int idx_new, // idx of new file + diffio_T *dio) // diff output +{ + FILE *fd = NULL; + int line_idx = 0; + diff_T *dprev = NULL; + diff_T *dp = curtab->tp_first_diff; + diff_T *dn, *dpl; + diffout_T *dout = &dio->dio_diff; + char_u linebuf[LBUFLEN]; // only need to hold the diff line + char_u *line; + long off; + int i; + int notset = TRUE; // block "*dp" not set yet + diffhunk_T *hunk = NULL; // init to avoid gcc warning + + enum { + DIFF_ED, + DIFF_UNIFIED, + DIFF_NONE + } diffstyle = DIFF_NONE; + + if (dout->dout_fname == NULL) + { + diffstyle = DIFF_UNIFIED; + } + else + { + fd = mch_fopen((char *)dout->dout_fname, "r"); + if (fd == NULL) + { + emsg(_(e_cannot_read_diff_output)); + return; + } + } + + if (!dio->dio_internal) + { + hunk = ALLOC_ONE(diffhunk_T); + if (hunk == NULL) + { + if (fd != NULL) + fclose(fd); + return; + } + } + + for (;;) + { + if (dio->dio_internal) + { + if (line_idx >= dout->dout_ga.ga_len) + break; // did last line + hunk = ((diffhunk_T **)dout->dout_ga.ga_data)[line_idx++]; + } + else + { + if (fd == NULL) + { + if (line_idx >= dout->dout_ga.ga_len) + break; // did last line + line = ((char_u **)dout->dout_ga.ga_data)[line_idx++]; + } + else + { + if (vim_fgets(linebuf, LBUFLEN, fd)) + break; // end of file + line = linebuf; + } + + if (diffstyle == DIFF_NONE) + { + // Determine diff style. + // ed like diff looks like this: + // {first}[,{last}]c{first}[,{last}] + // {first}a{first}[,{last}] + // {first}[,{last}]d{first} + // + // unified diff looks like this: + // --- file1 2018-03-20 13:23:35.783153140 +0100 + // +++ file2 2018-03-20 13:23:41.183156066 +0100 + // @@ -1,3 +1,5 @@ + if (isdigit(*line)) + diffstyle = DIFF_ED; + else if ((STRNCMP(line, "@@ ", 3) == 0)) + diffstyle = DIFF_UNIFIED; + else if ((STRNCMP(line, "--- ", 4) == 0) + && (vim_fgets(linebuf, LBUFLEN, fd) == 0) + && (STRNCMP(line, "+++ ", 4) == 0) + && (vim_fgets(linebuf, LBUFLEN, fd) == 0) + && (STRNCMP(line, "@@ ", 3) == 0)) + diffstyle = DIFF_UNIFIED; + else + // Format not recognized yet, skip over this line. Cygwin + // diff may put a warning at the start of the file. + continue; + } + + if (diffstyle == DIFF_ED) + { + if (!isdigit(*line)) + continue; // not the start of a diff block + if (parse_diff_ed(line, hunk) == FAIL) + continue; + } + else if (diffstyle == DIFF_UNIFIED) + { + if (STRNCMP(line, "@@ ", 3) != 0) + continue; // not the start of a diff block + if (parse_diff_unified(line, hunk) == FAIL) + continue; + } + else + { + emsg(_(e_invalid_diff_format)); + break; + } + } + + // Go over blocks before the change, for which orig and new are equal. + // Copy blocks from orig to new. + while (dp != NULL + && hunk->lnum_orig > dp->df_lnum[idx_orig] + + dp->df_count[idx_orig]) + { + if (notset) + diff_copy_entry(dprev, dp, idx_orig, idx_new); + dprev = dp; + dp = dp->df_next; + notset = TRUE; + } + + if (dp != NULL + && hunk->lnum_orig <= dp->df_lnum[idx_orig] + + dp->df_count[idx_orig] + && hunk->lnum_orig + hunk->count_orig >= dp->df_lnum[idx_orig]) + { + // New block overlaps with existing block(s). + // First find last block that overlaps. + for (dpl = dp; dpl->df_next != NULL; dpl = dpl->df_next) + if (hunk->lnum_orig + hunk->count_orig + < dpl->df_next->df_lnum[idx_orig]) + break; + + // If the newly found block starts before the old one, set the + // start back a number of lines. + off = dp->df_lnum[idx_orig] - hunk->lnum_orig; + if (off > 0) + { + for (i = idx_orig; i < idx_new; ++i) + if (curtab->tp_diffbuf[i] != NULL) + dp->df_lnum[i] -= off; + dp->df_lnum[idx_new] = hunk->lnum_new; + dp->df_count[idx_new] = hunk->count_new; + } + else if (notset) + { + // new block inside existing one, adjust new block + dp->df_lnum[idx_new] = hunk->lnum_new + off; + dp->df_count[idx_new] = hunk->count_new - off; + } + else + // second overlap of new block with existing block + dp->df_count[idx_new] += hunk->count_new - hunk->count_orig + + dpl->df_lnum[idx_orig] + dpl->df_count[idx_orig] + - (dp->df_lnum[idx_orig] + dp->df_count[idx_orig]); + + // Adjust the size of the block to include all the lines to the + // end of the existing block or the new diff, whatever ends last. + off = (hunk->lnum_orig + hunk->count_orig) + - (dpl->df_lnum[idx_orig] + dpl->df_count[idx_orig]); + if (off < 0) + { + // new change ends in existing block, adjust the end if not + // done already + if (notset) + dp->df_count[idx_new] += -off; + off = 0; + } + for (i = idx_orig; i < idx_new; ++i) + if (curtab->tp_diffbuf[i] != NULL) + dp->df_count[i] = dpl->df_lnum[i] + dpl->df_count[i] + - dp->df_lnum[i] + off; + + // Delete the diff blocks that have been merged into one. + dn = dp->df_next; + dp->df_next = dpl->df_next; + while (dn != dp->df_next) + { + dpl = dn->df_next; + vim_free(dn); + dn = dpl; + } + } + else + { + // Allocate a new diffblock. + dp = diff_alloc_new(curtab, dprev, dp); + if (dp == NULL) + goto done; + + dp->df_lnum[idx_orig] = hunk->lnum_orig; + dp->df_count[idx_orig] = hunk->count_orig; + dp->df_lnum[idx_new] = hunk->lnum_new; + dp->df_count[idx_new] = hunk->count_new; + + // Set values for other buffers, these must be equal to the + // original buffer, otherwise there would have been a change + // already. + for (i = idx_orig + 1; i < idx_new; ++i) + if (curtab->tp_diffbuf[i] != NULL) + diff_copy_entry(dprev, dp, idx_orig, i); + } + notset = FALSE; // "*dp" has been set + } + + // for remaining diff blocks orig and new are equal + while (dp != NULL) + { + if (notset) + diff_copy_entry(dprev, dp, idx_orig, idx_new); + dprev = dp; + dp = dp->df_next; + notset = TRUE; + } + +done: + if (!dio->dio_internal) + vim_free(hunk); + + if (fd != NULL) + fclose(fd); +} + +/* + * Copy an entry at "dp" from "idx_orig" to "idx_new". + */ + static void +diff_copy_entry( + diff_T *dprev, + diff_T *dp, + int idx_orig, + int idx_new) +{ + long off; + + if (dprev == NULL) + off = 0; + else + off = (dprev->df_lnum[idx_orig] + dprev->df_count[idx_orig]) + - (dprev->df_lnum[idx_new] + dprev->df_count[idx_new]); + dp->df_lnum[idx_new] = dp->df_lnum[idx_orig] - off; + dp->df_count[idx_new] = dp->df_count[idx_orig]; +} + +/* + * Clear the list of diffblocks for tab page "tp". + */ + void +diff_clear(tabpage_T *tp) +{ + diff_T *p, *next_p; + + for (p = tp->tp_first_diff; p != NULL; p = next_p) + { + next_p = p->df_next; + vim_free(p); + } + tp->tp_first_diff = NULL; +} + +/* + * Check diff status for line "lnum" in buffer "buf": + * Returns 0 for nothing special + * Returns -1 for a line that should be highlighted as changed. + * Returns -2 for a line that should be highlighted as added/deleted. + * Returns > 0 for inserting that many filler lines above it (never happens + * when 'diffopt' doesn't contain "filler"). + * This should only be used for windows where 'diff' is set. + */ + int +diff_check(win_T *wp, linenr_T lnum) +{ + int idx; // index in tp_diffbuf[] for this buffer + diff_T *dp; + int maxcount; + int i; + buf_T *buf = wp->w_buffer; + int cmp; + + if (curtab->tp_diff_invalid) + ex_diffupdate(NULL); // update after a big change + + if (curtab->tp_first_diff == NULL || !wp->w_p_diff) // no diffs at all + return 0; + + // safety check: "lnum" must be a buffer line + if (lnum < 1 || lnum > buf->b_ml.ml_line_count + 1) + return 0; + + idx = diff_buf_idx(buf); + if (idx == DB_COUNT) + return 0; // no diffs for buffer "buf" + +#ifdef FEAT_FOLDING + // A closed fold never has filler lines. + if (hasFoldingWin(wp, lnum, NULL, NULL, TRUE, NULL)) + return 0; +#endif + + // search for a change that includes "lnum" in the list of diffblocks. + FOR_ALL_DIFFBLOCKS_IN_TAB(curtab, dp) + if (lnum <= dp->df_lnum[idx] + dp->df_count[idx]) + break; + if (dp == NULL || lnum < dp->df_lnum[idx]) + return 0; + + if (lnum < dp->df_lnum[idx] + dp->df_count[idx]) + { + int zero = FALSE; + + // Changed or inserted line. If the other buffers have a count of + // zero, the lines were inserted. If the other buffers have the same + // count, check if the lines are identical. + cmp = FALSE; + for (i = 0; i < DB_COUNT; ++i) + if (i != idx && curtab->tp_diffbuf[i] != NULL) + { + if (dp->df_count[i] == 0) + zero = TRUE; + else + { + if (dp->df_count[i] != dp->df_count[idx]) + return -1; // nr of lines changed. + cmp = TRUE; + } + } + if (cmp) + { + // Compare all lines. If they are equal the lines were inserted + // in some buffers, deleted in others, but not changed. + for (i = 0; i < DB_COUNT; ++i) + if (i != idx && curtab->tp_diffbuf[i] != NULL + && dp->df_count[i] != 0) + if (!diff_equal_entry(dp, idx, i)) + return -1; + } + // If there is no buffer with zero lines then there is no difference + // any longer. Happens when making a change (or undo) that removes + // the difference. Can't remove the entry here, we might be halfway + // updating the window. Just report the text as unchanged. Other + // windows might still show the change though. + if (zero == FALSE) + return 0; + return -2; + } + + // If 'diffopt' doesn't contain "filler", return 0. + if (!(diff_flags & DIFF_FILLER)) + return 0; + + // Insert filler lines above the line just below the change. Will return + // 0 when this buf had the max count. + maxcount = 0; + for (i = 0; i < DB_COUNT; ++i) + if (curtab->tp_diffbuf[i] != NULL && dp->df_count[i] > maxcount) + maxcount = dp->df_count[i]; + return maxcount - dp->df_count[idx]; +} + +/* + * Compare two entries in diff "*dp" and return TRUE if they are equal. + */ + static int +diff_equal_entry(diff_T *dp, int idx1, int idx2) +{ + int i; + char_u *line; + int cmp; + + if (dp->df_count[idx1] != dp->df_count[idx2]) + return FALSE; + if (diff_check_sanity(curtab, dp) == FAIL) + return FALSE; + for (i = 0; i < dp->df_count[idx1]; ++i) + { + line = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx1], + dp->df_lnum[idx1] + i, FALSE)); + if (line == NULL) + return FALSE; + cmp = diff_cmp(line, ml_get_buf(curtab->tp_diffbuf[idx2], + dp->df_lnum[idx2] + i, FALSE)); + vim_free(line); + if (cmp != 0) + return FALSE; + } + return TRUE; +} + +/* + * Compare the characters at "p1" and "p2". If they are equal (possibly + * ignoring case) return TRUE and set "len" to the number of bytes. + */ + static int +diff_equal_char(char_u *p1, char_u *p2, int *len) +{ + int l = (*mb_ptr2len)(p1); + + if (l != (*mb_ptr2len)(p2)) + return FALSE; + if (l > 1) + { + if (STRNCMP(p1, p2, l) != 0 + && (!enc_utf8 + || !(diff_flags & DIFF_ICASE) + || utf_fold(utf_ptr2char(p1)) + != utf_fold(utf_ptr2char(p2)))) + return FALSE; + *len = l; + } + else + { + if ((*p1 != *p2) + && (!(diff_flags & DIFF_ICASE) + || TOLOWER_LOC(*p1) != TOLOWER_LOC(*p2))) + return FALSE; + *len = 1; + } + return TRUE; +} + +/* + * Compare strings "s1" and "s2" according to 'diffopt'. + * Return non-zero when they are different. + */ + static int +diff_cmp(char_u *s1, char_u *s2) +{ + char_u *p1, *p2; + int l; + + if ((diff_flags & DIFF_IBLANK) + && (*skipwhite(s1) == NUL || *skipwhite(s2) == NUL)) + return 0; + + if ((diff_flags & (DIFF_ICASE | ALL_WHITE_DIFF)) == 0) + return STRCMP(s1, s2); + if ((diff_flags & DIFF_ICASE) && !(diff_flags & ALL_WHITE_DIFF)) + return MB_STRICMP(s1, s2); + + p1 = s1; + p2 = s2; + + // Ignore white space changes and possibly ignore case. + while (*p1 != NUL && *p2 != NUL) + { + if (((diff_flags & DIFF_IWHITE) + && VIM_ISWHITE(*p1) && VIM_ISWHITE(*p2)) + || ((diff_flags & DIFF_IWHITEALL) + && (VIM_ISWHITE(*p1) || VIM_ISWHITE(*p2)))) + { + p1 = skipwhite(p1); + p2 = skipwhite(p2); + } + else + { + if (!diff_equal_char(p1, p2, &l)) + break; + p1 += l; + p2 += l; + } + } + + // Ignore trailing white space. + p1 = skipwhite(p1); + p2 = skipwhite(p2); + if (*p1 != NUL || *p2 != NUL) + return 1; + return 0; +} + +/* + * Return the number of filler lines above "lnum". + */ + int +diff_check_fill(win_T *wp, linenr_T lnum) +{ + int n; + + // be quick when there are no filler lines + if (!(diff_flags & DIFF_FILLER)) + return 0; + n = diff_check(wp, lnum); + if (n <= 0) + return 0; + return n; +} + +/* + * Set the topline of "towin" to match the position in "fromwin", so that they + * show the same diff'ed lines. + */ + void +diff_set_topline(win_T *fromwin, win_T *towin) +{ + buf_T *frombuf = fromwin->w_buffer; + linenr_T lnum = fromwin->w_topline; + int fromidx; + int toidx; + diff_T *dp; + int max_count; + int i; + + fromidx = diff_buf_idx(frombuf); + if (fromidx == DB_COUNT) + return; // safety check + + if (curtab->tp_diff_invalid) + ex_diffupdate(NULL); // update after a big change + + towin->w_topfill = 0; + + // search for a change that includes "lnum" in the list of diffblocks. + FOR_ALL_DIFFBLOCKS_IN_TAB(curtab, dp) + if (lnum <= dp->df_lnum[fromidx] + dp->df_count[fromidx]) + break; + if (dp == NULL) + { + // After last change, compute topline relative to end of file; no + // filler lines. + towin->w_topline = towin->w_buffer->b_ml.ml_line_count + - (frombuf->b_ml.ml_line_count - lnum); + } + else + { + // Find index for "towin". + toidx = diff_buf_idx(towin->w_buffer); + if (toidx == DB_COUNT) + return; // safety check + + towin->w_topline = lnum + (dp->df_lnum[toidx] - dp->df_lnum[fromidx]); + if (lnum >= dp->df_lnum[fromidx]) + { + // Inside a change: compute filler lines. With three or more + // buffers we need to know the largest count. + max_count = 0; + for (i = 0; i < DB_COUNT; ++i) + if (curtab->tp_diffbuf[i] != NULL + && max_count < dp->df_count[i]) + max_count = dp->df_count[i]; + + if (dp->df_count[toidx] == dp->df_count[fromidx]) + { + // same number of lines: use same filler count + towin->w_topfill = fromwin->w_topfill; + } + else if (dp->df_count[toidx] > dp->df_count[fromidx]) + { + if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx]) + { + // more lines in towin and fromwin doesn't show diff + // lines, only filler lines + if (max_count - fromwin->w_topfill >= dp->df_count[toidx]) + { + // towin also only shows filler lines + towin->w_topline = dp->df_lnum[toidx] + + dp->df_count[toidx]; + towin->w_topfill = fromwin->w_topfill; + } + else + // towin still has some diff lines to show + towin->w_topline = dp->df_lnum[toidx] + + max_count - fromwin->w_topfill; + } + } + else if (towin->w_topline >= dp->df_lnum[toidx] + + dp->df_count[toidx]) + { + // less lines in towin and no diff lines to show: compute + // filler lines + towin->w_topline = dp->df_lnum[toidx] + dp->df_count[toidx]; + if (diff_flags & DIFF_FILLER) + { + if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx]) + // fromwin is also out of diff lines + towin->w_topfill = fromwin->w_topfill; + else + // fromwin has some diff lines + towin->w_topfill = dp->df_lnum[fromidx] + + max_count - lnum; + } + } + } + } + + // safety check (if diff info gets outdated strange things may happen) + towin->w_botfill = FALSE; + if (towin->w_topline > towin->w_buffer->b_ml.ml_line_count) + { + towin->w_topline = towin->w_buffer->b_ml.ml_line_count; + towin->w_botfill = TRUE; + } + if (towin->w_topline < 1) + { + towin->w_topline = 1; + towin->w_topfill = 0; + } + + // When w_topline changes need to recompute w_botline and cursor position + invalidate_botline_win(towin); + changed_line_abv_curs_win(towin); + + check_topfill(towin, FALSE); +#ifdef FEAT_FOLDING + (void)hasFoldingWin(towin, towin->w_topline, &towin->w_topline, + NULL, TRUE, NULL); +#endif +} + +/* + * This is called when 'diffopt' is changed. + */ + int +diffopt_changed(void) +{ + char_u *p; + int diff_context_new = 6; + int diff_flags_new = 0; + int diff_foldcolumn_new = 2; + long diff_algorithm_new = 0; + long diff_indent_heuristic = 0; + tabpage_T *tp; + + p = p_dip; + while (*p != NUL) + { + if (STRNCMP(p, "filler", 6) == 0) + { + p += 6; + diff_flags_new |= DIFF_FILLER; + } + else if (STRNCMP(p, "context:", 8) == 0 && VIM_ISDIGIT(p[8])) + { + p += 8; + diff_context_new = getdigits(&p); + } + else if (STRNCMP(p, "iblank", 6) == 0) + { + p += 6; + diff_flags_new |= DIFF_IBLANK; + } + else if (STRNCMP(p, "icase", 5) == 0) + { + p += 5; + diff_flags_new |= DIFF_ICASE; + } + else if (STRNCMP(p, "iwhiteall", 9) == 0) + { + p += 9; + diff_flags_new |= DIFF_IWHITEALL; + } + else if (STRNCMP(p, "iwhiteeol", 9) == 0) + { + p += 9; + diff_flags_new |= DIFF_IWHITEEOL; + } + else if (STRNCMP(p, "iwhite", 6) == 0) + { + p += 6; + diff_flags_new |= DIFF_IWHITE; + } + else if (STRNCMP(p, "horizontal", 10) == 0) + { + p += 10; + diff_flags_new |= DIFF_HORIZONTAL; + } + else if (STRNCMP(p, "vertical", 8) == 0) + { + p += 8; + diff_flags_new |= DIFF_VERTICAL; + } + else if (STRNCMP(p, "foldcolumn:", 11) == 0 && VIM_ISDIGIT(p[11])) + { + p += 11; + diff_foldcolumn_new = getdigits(&p); + } + else if (STRNCMP(p, "hiddenoff", 9) == 0) + { + p += 9; + diff_flags_new |= DIFF_HIDDEN_OFF; + } + else if (STRNCMP(p, "closeoff", 8) == 0) + { + p += 8; + diff_flags_new |= DIFF_CLOSE_OFF; + } + else if (STRNCMP(p, "followwrap", 10) == 0) + { + p += 10; + diff_flags_new |= DIFF_FOLLOWWRAP; + } + else if (STRNCMP(p, "indent-heuristic", 16) == 0) + { + p += 16; + diff_indent_heuristic = XDF_INDENT_HEURISTIC; + } + else if (STRNCMP(p, "internal", 8) == 0) + { + p += 8; + diff_flags_new |= DIFF_INTERNAL; + } + else if (STRNCMP(p, "algorithm:", 10) == 0) + { + p += 10; + if (STRNCMP(p, "myers", 5) == 0) + { + p += 5; + diff_algorithm_new = 0; + } + else if (STRNCMP(p, "minimal", 7) == 0) + { + p += 7; + diff_algorithm_new = XDF_NEED_MINIMAL; + } + else if (STRNCMP(p, "patience", 8) == 0) + { + p += 8; + diff_algorithm_new = XDF_PATIENCE_DIFF; + } + else if (STRNCMP(p, "histogram", 9) == 0) + { + p += 9; + diff_algorithm_new = XDF_HISTOGRAM_DIFF; + } + else + return FAIL; + } + + if (*p != ',' && *p != NUL) + return FAIL; + if (*p == ',') + ++p; + } + + diff_algorithm_new |= diff_indent_heuristic; + + // Can't have both "horizontal" and "vertical". + if ((diff_flags_new & DIFF_HORIZONTAL) && (diff_flags_new & DIFF_VERTICAL)) + return FAIL; + + // If flags were added or removed, or the algorithm was changed, need to + // update the diff. + if (diff_flags != diff_flags_new || diff_algorithm != diff_algorithm_new) + FOR_ALL_TABPAGES(tp) + tp->tp_diff_invalid = TRUE; + + diff_flags = diff_flags_new; + diff_context = diff_context_new == 0 ? 1 : diff_context_new; + diff_foldcolumn = diff_foldcolumn_new; + diff_algorithm = diff_algorithm_new; + + diff_redraw(TRUE); + + // recompute the scroll binding with the new option value, may + // remove or add filler lines + check_scrollbind((linenr_T)0, 0L); + + return OK; +} + +/* + * Return TRUE if 'diffopt' contains "horizontal". + */ + int +diffopt_horizontal(void) +{ + return (diff_flags & DIFF_HORIZONTAL) != 0; +} + +/* + * Return TRUE if 'diffopt' contains "hiddenoff". + */ + int +diffopt_hiddenoff(void) +{ + return (diff_flags & DIFF_HIDDEN_OFF) != 0; +} + +/* + * Return TRUE if 'diffopt' contains "closeoff". + */ + int +diffopt_closeoff(void) +{ + return (diff_flags & DIFF_CLOSE_OFF) != 0; +} + +/* + * Find the difference within a changed line. + * Returns TRUE if the line was added, no other buffer has it. + */ + int +diff_find_change( + win_T *wp, + linenr_T lnum, + int *startp, // first char of the change + int *endp) // last char of the change +{ + char_u *line_org; + char_u *line_new; + int i; + int si_org, si_new; + int ei_org, ei_new; + diff_T *dp; + int idx; + int off; + int added = TRUE; + char_u *p1, *p2; + int l; + + // Make a copy of the line, the next ml_get() will invalidate it. + line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, FALSE)); + if (line_org == NULL) + return FALSE; + + idx = diff_buf_idx(wp->w_buffer); + if (idx == DB_COUNT) // cannot happen + { + vim_free(line_org); + return FALSE; + } + + // search for a change that includes "lnum" in the list of diffblocks. + FOR_ALL_DIFFBLOCKS_IN_TAB(curtab, dp) + if (lnum <= dp->df_lnum[idx] + dp->df_count[idx]) + break; + if (dp == NULL || diff_check_sanity(curtab, dp) == FAIL) + { + vim_free(line_org); + return FALSE; + } + + off = lnum - dp->df_lnum[idx]; + + for (i = 0; i < DB_COUNT; ++i) + if (curtab->tp_diffbuf[i] != NULL && i != idx) + { + // Skip lines that are not in the other change (filler lines). + if (off >= dp->df_count[i]) + continue; + added = FALSE; + line_new = ml_get_buf(curtab->tp_diffbuf[i], + dp->df_lnum[i] + off, FALSE); + + // Search for start of difference + si_org = si_new = 0; + while (line_org[si_org] != NUL) + { + if (((diff_flags & DIFF_IWHITE) + && VIM_ISWHITE(line_org[si_org]) + && VIM_ISWHITE(line_new[si_new])) + || ((diff_flags & DIFF_IWHITEALL) + && (VIM_ISWHITE(line_org[si_org]) + || VIM_ISWHITE(line_new[si_new])))) + { + si_org = (int)(skipwhite(line_org + si_org) - line_org); + si_new = (int)(skipwhite(line_new + si_new) - line_new); + } + else + { + if (!diff_equal_char(line_org + si_org, line_new + si_new, + &l)) + break; + si_org += l; + si_new += l; + } + } + if (has_mbyte) + { + // Move back to first byte of character in both lines (may + // have "nn^" in line_org and "n^ in line_new). + si_org -= (*mb_head_off)(line_org, line_org + si_org); + si_new -= (*mb_head_off)(line_new, line_new + si_new); + } + if (*startp > si_org) + *startp = si_org; + + // Search for end of difference, if any. + if (line_org[si_org] != NUL || line_new[si_new] != NUL) + { + ei_org = (int)STRLEN(line_org); + ei_new = (int)STRLEN(line_new); + while (ei_org >= *startp && ei_new >= si_new + && ei_org >= 0 && ei_new >= 0) + { + if (((diff_flags & DIFF_IWHITE) + && VIM_ISWHITE(line_org[ei_org]) + && VIM_ISWHITE(line_new[ei_new])) + || ((diff_flags & DIFF_IWHITEALL) + && (VIM_ISWHITE(line_org[ei_org]) + || VIM_ISWHITE(line_new[ei_new])))) + { + while (ei_org >= *startp + && VIM_ISWHITE(line_org[ei_org])) + --ei_org; + while (ei_new >= si_new + && VIM_ISWHITE(line_new[ei_new])) + --ei_new; + } + else + { + p1 = line_org + ei_org; + p2 = line_new + ei_new; + p1 -= (*mb_head_off)(line_org, p1); + p2 -= (*mb_head_off)(line_new, p2); + if (!diff_equal_char(p1, p2, &l)) + break; + ei_org -= l; + ei_new -= l; + } + } + if (*endp < ei_org) + *endp = ei_org; + } + } + + vim_free(line_org); + return added; +} + +#if defined(FEAT_FOLDING) || defined(PROTO) +/* + * Return TRUE if line "lnum" is not close to a diff block, this line should + * be in a fold. + * Return FALSE if there are no diff blocks at all in this window. + */ + int +diff_infold(win_T *wp, linenr_T lnum) +{ + int i; + int idx = -1; + int other = FALSE; + diff_T *dp; + + // Return if 'diff' isn't set. + if (!wp->w_p_diff) + return FALSE; + + for (i = 0; i < DB_COUNT; ++i) + { + if (curtab->tp_diffbuf[i] == wp->w_buffer) + idx = i; + else if (curtab->tp_diffbuf[i] != NULL) + other = TRUE; + } + + // return here if there are no diffs in the window + if (idx == -1 || !other) + return FALSE; + + if (curtab->tp_diff_invalid) + ex_diffupdate(NULL); // update after a big change + + // Return if there are no diff blocks. All lines will be folded. + if (curtab->tp_first_diff == NULL) + return TRUE; + + FOR_ALL_DIFFBLOCKS_IN_TAB(curtab, dp) + { + // If this change is below the line there can't be any further match. + if (dp->df_lnum[idx] - diff_context > lnum) + break; + // If this change ends before the line we have a match. + if (dp->df_lnum[idx] + dp->df_count[idx] + diff_context > lnum) + return FALSE; + } + return TRUE; +} +#endif + +/* + * "dp" and "do" commands. + */ + void +nv_diffgetput(int put, long count) +{ + exarg_T ea; + char_u buf[30]; + +#ifdef FEAT_JOB_CHANNEL + if (bt_prompt(curbuf)) + { + vim_beep(BO_OPER); + return; + } +#endif + if (count == 0) + ea.arg = (char_u *)""; + else + { + vim_snprintf((char *)buf, 30, "%ld", count); + ea.arg = buf; + } + if (put) + ea.cmdidx = CMD_diffput; + else + ea.cmdidx = CMD_diffget; + ea.addr_count = 0; + ea.line1 = curwin->w_cursor.lnum; + ea.line2 = curwin->w_cursor.lnum; + ex_diffgetput(&ea); +} + +/* + * Return TRUE if "diff" appears in the list of diff blocks of the current tab. + */ + static int +valid_diff(diff_T *diff) +{ + diff_T *dp; + + for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next) + if (dp == diff) + return TRUE; + return FALSE; +} + +/* + * ":diffget" + * ":diffput" + */ + void +ex_diffgetput(exarg_T *eap) +{ + linenr_T lnum; + int count; + linenr_T off = 0; + diff_T *dp; + diff_T *dprev; + diff_T *dfree; + int idx_cur; + int idx_other; + int idx_from; + int idx_to; + int i; + int added; + char_u *p; + aco_save_T aco; + buf_T *buf; + int start_skip, end_skip; + int new_count; + int buf_empty; + int found_not_ma = FALSE; + + // Find the current buffer in the list of diff buffers. + idx_cur = diff_buf_idx(curbuf); + if (idx_cur == DB_COUNT) + { + emsg(_(e_current_buffer_is_not_in_diff_mode)); + return; + } + + if (*eap->arg == NUL) + { + // No argument: Find the other buffer in the list of diff buffers. + for (idx_other = 0; idx_other < DB_COUNT; ++idx_other) + if (curtab->tp_diffbuf[idx_other] != curbuf + && curtab->tp_diffbuf[idx_other] != NULL) + { + if (eap->cmdidx != CMD_diffput + || curtab->tp_diffbuf[idx_other]->b_p_ma) + break; + found_not_ma = TRUE; + } + if (idx_other == DB_COUNT) + { + if (found_not_ma) + emsg(_(e_no_other_buffer_in_diff_mode_is_modifiable)); + else + emsg(_(e_no_other_buffer_in_diff_mode)); + return; + } + + // Check that there isn't a third buffer in the list + for (i = idx_other + 1; i < DB_COUNT; ++i) + if (curtab->tp_diffbuf[i] != curbuf + && curtab->tp_diffbuf[i] != NULL + && (eap->cmdidx != CMD_diffput || curtab->tp_diffbuf[i]->b_p_ma)) + { + emsg(_(e_more_than_two_buffers_in_diff_mode_dont_know_which_one_to_use)); + return; + } + } + else + { + // Buffer number or pattern given. Ignore trailing white space. + p = eap->arg + STRLEN(eap->arg); + while (p > eap->arg && VIM_ISWHITE(p[-1])) + --p; + for (i = 0; vim_isdigit(eap->arg[i]) && eap->arg + i < p; ++i) + ; + if (eap->arg + i == p) // digits only + i = atol((char *)eap->arg); + else + { + i = buflist_findpat(eap->arg, p, FALSE, TRUE, FALSE); + if (i < 0) + return; // error message already given + } + buf = buflist_findnr(i); + if (buf == NULL) + { + semsg(_(e_cant_find_buffer_str), eap->arg); + return; + } + if (buf == curbuf) + return; // nothing to do + idx_other = diff_buf_idx(buf); + if (idx_other == DB_COUNT) + { + semsg(_(e_buffer_str_is_not_in_diff_mode), eap->arg); + return; + } + } + + diff_busy = TRUE; + + // When no range given include the line above or below the cursor. + if (eap->addr_count == 0) + { + // Make it possible that ":diffget" on the last line gets line below + // the cursor line when there is no difference above the cursor. + if (eap->cmdidx == CMD_diffget + && eap->line1 == curbuf->b_ml.ml_line_count + && diff_check(curwin, eap->line1) == 0 + && (eap->line1 == 1 || diff_check(curwin, eap->line1 - 1) == 0)) + ++eap->line2; + else if (eap->line1 > 0) + --eap->line1; + } + + if (eap->cmdidx == CMD_diffget) + { + idx_from = idx_other; + idx_to = idx_cur; + } + else + { + idx_from = idx_cur; + idx_to = idx_other; + // Need to make the other buffer the current buffer to be able to make + // changes in it. + // Set curwin/curbuf to buf and save a few things. + aucmd_prepbuf(&aco, curtab->tp_diffbuf[idx_other]); + if (curbuf != curtab->tp_diffbuf[idx_other]) + // Could not find a window for this buffer, the rest is likely to + // fail. + goto theend; + } + + // May give the warning for a changed buffer here, which can trigger the + // FileChangedRO autocommand, which may do nasty things and mess + // everything up. + if (!curbuf->b_changed) + { + change_warning(0); + if (diff_buf_idx(curbuf) != idx_to) + { + emsg(_(e_buffer_changed_unexpectedly)); + goto theend; + } + } + + dprev = NULL; + for (dp = curtab->tp_first_diff; dp != NULL; ) + { + if (dp->df_lnum[idx_cur] > eap->line2 + off) + break; // past the range that was specified + + dfree = NULL; + lnum = dp->df_lnum[idx_to]; + count = dp->df_count[idx_to]; + if (dp->df_lnum[idx_cur] + dp->df_count[idx_cur] > eap->line1 + off + && u_save(lnum - 1, lnum + count) != FAIL) + { + // Inside the specified range and saving for undo worked. + start_skip = 0; + end_skip = 0; + if (eap->addr_count > 0) + { + // A range was specified: check if lines need to be skipped. + start_skip = eap->line1 + off - dp->df_lnum[idx_cur]; + if (start_skip > 0) + { + // range starts below start of current diff block + if (start_skip > count) + { + lnum += count; + count = 0; + } + else + { + count -= start_skip; + lnum += start_skip; + } + } + else + start_skip = 0; + + end_skip = dp->df_lnum[idx_cur] + dp->df_count[idx_cur] - 1 + - (eap->line2 + off); + if (end_skip > 0) + { + // range ends above end of current/from diff block + if (idx_cur == idx_from) // :diffput + { + i = dp->df_count[idx_cur] - start_skip - end_skip; + if (count > i) + count = i; + } + else // :diffget + { + count -= end_skip; + end_skip = dp->df_count[idx_from] - start_skip - count; + if (end_skip < 0) + end_skip = 0; + } + } + else + end_skip = 0; + } + + buf_empty = BUFEMPTY(); + added = 0; + for (i = 0; i < count; ++i) + { + // remember deleting the last line of the buffer + buf_empty = curbuf->b_ml.ml_line_count == 1; + if (ml_delete(lnum) == OK) + --added; + } + for (i = 0; i < dp->df_count[idx_from] - start_skip - end_skip; ++i) + { + linenr_T nr; + + nr = dp->df_lnum[idx_from] + start_skip + i; + if (nr > curtab->tp_diffbuf[idx_from]->b_ml.ml_line_count) + break; + p = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx_from], + nr, FALSE)); + if (p != NULL) + { + ml_append(lnum + i - 1, p, 0, FALSE); + vim_free(p); + ++added; + if (buf_empty && curbuf->b_ml.ml_line_count == 2) + { + // Added the first line into an empty buffer, need to + // delete the dummy empty line. + buf_empty = FALSE; + ml_delete((linenr_T)2); + } + } + } + new_count = dp->df_count[idx_to] + added; + dp->df_count[idx_to] = new_count; + + if (start_skip == 0 && end_skip == 0) + { + // Check if there are any other buffers and if the diff is + // equal in them. + for (i = 0; i < DB_COUNT; ++i) + if (curtab->tp_diffbuf[i] != NULL && i != idx_from + && i != idx_to + && !diff_equal_entry(dp, idx_from, i)) + break; + if (i == DB_COUNT) + { + // delete the diff entry, the buffers are now equal here + dfree = dp; + dp = dp->df_next; + if (dprev == NULL) + curtab->tp_first_diff = dp; + else + dprev->df_next = dp; + } + } + + if (added != 0) + { + // Adjust marks. This will change the following entries! + mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, (long)added); + if (curwin->w_cursor.lnum >= lnum) + { + // Adjust the cursor position if it's in/after the changed + // lines. + if (curwin->w_cursor.lnum >= lnum + count) + curwin->w_cursor.lnum += added; + else if (added < 0) + curwin->w_cursor.lnum = lnum; + } + } + changed_lines(lnum, 0, lnum + count, (long)added); + + if (dfree != NULL) + { + // Diff is deleted, update folds in other windows. +#ifdef FEAT_FOLDING + diff_fold_update(dfree, idx_to); +#endif + vim_free(dfree); + } + + // mark_adjust() may have made "dp" invalid. We don't know where + // to continue then, bail out. + if (added != 0 && !valid_diff(dp)) + break; + + if (dfree == NULL) + // mark_adjust() may have changed the count in a wrong way + dp->df_count[idx_to] = new_count; + + // When changing the current buffer, keep track of line numbers + if (idx_cur == idx_to) + off += added; + } + + // If before the range or not deleted, go to next diff. + if (dfree == NULL) + { + dprev = dp; + dp = dp->df_next; + } + } + + // restore curwin/curbuf and a few other things + if (eap->cmdidx != CMD_diffget) + { + // Syncing undo only works for the current buffer, but we change + // another buffer. Sync undo if the command was typed. This isn't + // 100% right when ":diffput" is used in a function or mapping. + if (KeyTyped) + u_sync(FALSE); + aucmd_restbuf(&aco); + } + +theend: + diff_busy = FALSE; + if (diff_need_update) + ex_diffupdate(NULL); + + // Check that the cursor is on a valid character and update its + // position. When there were filler lines the topline has become + // invalid. + check_cursor(); + changed_line_abv_curs(); + + if (diff_need_update) + // redraw already done by ex_diffupdate() + diff_need_update = FALSE; + else + { + // Also need to redraw the other buffers. + diff_redraw(FALSE); + apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, FALSE, curbuf); + } +} + +#ifdef FEAT_FOLDING +/* + * Update folds for all diff buffers for entry "dp". + * Skip buffer with index "skip_idx". + * When there are no diffs, all folds are removed. + */ + static void +diff_fold_update(diff_T *dp, int skip_idx) +{ + int i; + win_T *wp; + + FOR_ALL_WINDOWS(wp) + for (i = 0; i < DB_COUNT; ++i) + if (curtab->tp_diffbuf[i] == wp->w_buffer && i != skip_idx) + foldUpdate(wp, dp->df_lnum[i], + dp->df_lnum[i] + dp->df_count[i]); +} +#endif + +/* + * Return TRUE if buffer "buf" is in diff-mode. + */ + int +diff_mode_buf(buf_T *buf) +{ + tabpage_T *tp; + + FOR_ALL_TABPAGES(tp) + if (diff_buf_idx_tp(buf, tp) != DB_COUNT) + return TRUE; + return FALSE; +} + +/* + * Move "count" times in direction "dir" to the next diff block. + * Return FAIL if there isn't such a diff block. + */ + int +diff_move_to(int dir, long count) +{ + int idx; + linenr_T lnum = curwin->w_cursor.lnum; + diff_T *dp; + + idx = diff_buf_idx(curbuf); + if (idx == DB_COUNT || curtab->tp_first_diff == NULL) + return FAIL; + + if (curtab->tp_diff_invalid) + ex_diffupdate(NULL); // update after a big change + + if (curtab->tp_first_diff == NULL) // no diffs today + return FAIL; + + while (--count >= 0) + { + // Check if already before first diff. + if (dir == BACKWARD && lnum <= curtab->tp_first_diff->df_lnum[idx]) + break; + + for (dp = curtab->tp_first_diff; ; dp = dp->df_next) + { + if (dp == NULL) + break; + if ((dir == FORWARD && lnum < dp->df_lnum[idx]) + || (dir == BACKWARD + && (dp->df_next == NULL + || lnum <= dp->df_next->df_lnum[idx]))) + { + lnum = dp->df_lnum[idx]; + break; + } + } + } + + // don't end up past the end of the file + if (lnum > curbuf->b_ml.ml_line_count) + lnum = curbuf->b_ml.ml_line_count; + + // When the cursor didn't move at all we fail. + if (lnum == curwin->w_cursor.lnum) + return FAIL; + + setpcmark(); + curwin->w_cursor.lnum = lnum; + curwin->w_cursor.col = 0; + + return OK; +} + +/* + * Return the line number in the current window that is closest to "lnum1" in + * "buf1" in diff mode. + */ + static linenr_T +diff_get_corresponding_line_int( + buf_T *buf1, + linenr_T lnum1) +{ + int idx1; + int idx2; + diff_T *dp; + int baseline = 0; + + idx1 = diff_buf_idx(buf1); + idx2 = diff_buf_idx(curbuf); + if (idx1 == DB_COUNT || idx2 == DB_COUNT || curtab->tp_first_diff == NULL) + return lnum1; + + if (curtab->tp_diff_invalid) + ex_diffupdate(NULL); // update after a big change + + if (curtab->tp_first_diff == NULL) // no diffs today + return lnum1; + + FOR_ALL_DIFFBLOCKS_IN_TAB(curtab, dp) + { + if (dp->df_lnum[idx1] > lnum1) + return lnum1 - baseline; + if ((dp->df_lnum[idx1] + dp->df_count[idx1]) > lnum1) + { + // Inside the diffblock + baseline = lnum1 - dp->df_lnum[idx1]; + if (baseline > dp->df_count[idx2]) + baseline = dp->df_count[idx2]; + + return dp->df_lnum[idx2] + baseline; + } + if ( (dp->df_lnum[idx1] == lnum1) + && (dp->df_count[idx1] == 0) + && (dp->df_lnum[idx2] <= curwin->w_cursor.lnum) + && ((dp->df_lnum[idx2] + dp->df_count[idx2]) + > curwin->w_cursor.lnum)) + /* + * Special case: if the cursor is just after a zero-count + * block (i.e. all filler) and the target cursor is already + * inside the corresponding block, leave the target cursor + * unmoved. This makes repeated CTRL-W W operations work + * as expected. + */ + return curwin->w_cursor.lnum; + baseline = (dp->df_lnum[idx1] + dp->df_count[idx1]) + - (dp->df_lnum[idx2] + dp->df_count[idx2]); + } + + // If we get here then the cursor is after the last diff + return lnum1 - baseline; +} + +/* + * Return the line number in the current window that is closest to "lnum1" in + * "buf1" in diff mode. Checks the line number to be valid. + */ + linenr_T +diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1) +{ + linenr_T lnum = diff_get_corresponding_line_int(buf1, lnum1); + + // don't end up past the end of the file + if (lnum > curbuf->b_ml.ml_line_count) + return curbuf->b_ml.ml_line_count; + return lnum; +} + +/* + * For line "lnum" in the current window find the equivalent lnum in window + * "wp", compensating for inserted/deleted lines. + */ + linenr_T +diff_lnum_win(linenr_T lnum, win_T *wp) +{ + diff_T *dp; + int idx; + int i; + linenr_T n; + + idx = diff_buf_idx(curbuf); + if (idx == DB_COUNT) // safety check + return (linenr_T)0; + + if (curtab->tp_diff_invalid) + ex_diffupdate(NULL); // update after a big change + + // search for a change that includes "lnum" in the list of diffblocks. + FOR_ALL_DIFFBLOCKS_IN_TAB(curtab, dp) + if (lnum <= dp->df_lnum[idx] + dp->df_count[idx]) + break; + + // When after the last change, compute relative to the last line number. + if (dp == NULL) + return wp->w_buffer->b_ml.ml_line_count + - (curbuf->b_ml.ml_line_count - lnum); + + // Find index for "wp". + i = diff_buf_idx(wp->w_buffer); + if (i == DB_COUNT) // safety check + return (linenr_T)0; + + n = lnum + (dp->df_lnum[i] - dp->df_lnum[idx]); + if (n > dp->df_lnum[i] + dp->df_count[i]) + n = dp->df_lnum[i] + dp->df_count[i]; + return n; +} + +/* + * Handle an ED style diff line. + * Return FAIL if the line does not contain diff info. + */ + static int +parse_diff_ed( + char_u *line, + diffhunk_T *hunk) +{ + char_u *p; + long f1, l1, f2, l2; + int difftype; + + // The line must be one of three formats: + // change: {first}[,{last}]c{first}[,{last}] + // append: {first}a{first}[,{last}] + // delete: {first}[,{last}]d{first} + p = line; + f1 = getdigits(&p); + if (*p == ',') + { + ++p; + l1 = getdigits(&p); + } + else + l1 = f1; + if (*p != 'a' && *p != 'c' && *p != 'd') + return FAIL; // invalid diff format + difftype = *p++; + f2 = getdigits(&p); + if (*p == ',') + { + ++p; + l2 = getdigits(&p); + } + else + l2 = f2; + if (l1 < f1 || l2 < f2) + return FAIL; + + if (difftype == 'a') + { + hunk->lnum_orig = f1 + 1; + hunk->count_orig = 0; + } + else + { + hunk->lnum_orig = f1; + hunk->count_orig = l1 - f1 + 1; + } + if (difftype == 'd') + { + hunk->lnum_new = f2 + 1; + hunk->count_new = 0; + } + else + { + hunk->lnum_new = f2; + hunk->count_new = l2 - f2 + 1; + } + return OK; +} + +/* + * Parses unified diff with zero(!) context lines. + * Return FAIL if there is no diff information in "line". + */ + static int +parse_diff_unified( + char_u *line, + diffhunk_T *hunk) +{ + char_u *p; + long oldline, oldcount, newline, newcount; + + // Parse unified diff hunk header: + // @@ -oldline,oldcount +newline,newcount @@ + p = line; + if (*p++ == '@' && *p++ == '@' && *p++ == ' ' && *p++ == '-') + { + oldline = getdigits(&p); + if (*p == ',') + { + ++p; + oldcount = getdigits(&p); + } + else + oldcount = 1; + if (*p++ == ' ' && *p++ == '+') + { + newline = getdigits(&p); + if (*p == ',') + { + ++p; + newcount = getdigits(&p); + } + else + newcount = 1; + } + else + return FAIL; // invalid diff format + + if (oldcount == 0) + oldline += 1; + if (newcount == 0) + newline += 1; + if (newline == 0) + newline = 1; + + hunk->lnum_orig = oldline; + hunk->count_orig = oldcount; + hunk->lnum_new = newline; + hunk->count_new = newcount; + + return OK; + } + + return FAIL; +} + +/* + * Callback function for the xdl_diff() function. + * Stores the diff output in a grow array. + */ + static int +xdiff_out( + long start_a, + long count_a, + long start_b, + long count_b, + void *priv) +{ + diffout_T *dout = (diffout_T *)priv; + diffhunk_T *p = ALLOC_ONE(diffhunk_T); + + if (p == NULL) + return -1; + + if (ga_grow(&dout->dout_ga, 1) == FAIL) + { + vim_free(p); + return -1; + } + + p->lnum_orig = start_a + 1; + p->count_orig = count_a; + p->lnum_new = start_b + 1; + p->count_new = count_b; + ((diffhunk_T **)dout->dout_ga.ga_data)[dout->dout_ga.ga_len++] = p; + return 0; +} + +#endif // FEAT_DIFF + +#if defined(FEAT_EVAL) || defined(PROTO) + +/* + * "diff_filler()" function + */ + void +f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +#ifdef FEAT_DIFF + if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL) + return; + + rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars)); +#endif +} + +/* + * "diff_hlID()" function + */ + void +f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +#ifdef FEAT_DIFF + linenr_T lnum; + static linenr_T prev_lnum = 0; + static varnumber_T changedtick = 0; + static int fnum = 0; + static int change_start = 0; + static int change_end = 0; + static hlf_T hlID = (hlf_T)0; + int filler_lines; + int col; + + if (in_vim9script() + && (check_for_lnum_arg(argvars,0) == FAIL + || check_for_number_arg(argvars, 1) == FAIL)) + return; + + lnum = tv_get_lnum(argvars); + if (lnum < 0) // ignore type error in {lnum} arg + lnum = 0; + if (lnum != prev_lnum + || changedtick != CHANGEDTICK(curbuf) + || fnum != curbuf->b_fnum) + { + // New line, buffer, change: need to get the values. + filler_lines = diff_check(curwin, lnum); + if (filler_lines < 0) + { + if (filler_lines == -1) + { + change_start = MAXCOL; + change_end = -1; + if (diff_find_change(curwin, lnum, &change_start, &change_end)) + hlID = HLF_ADD; // added line + else + hlID = HLF_CHD; // changed line + } + else + hlID = HLF_ADD; // added line + } + else + hlID = (hlf_T)0; + prev_lnum = lnum; + changedtick = CHANGEDTICK(curbuf); + fnum = curbuf->b_fnum; + } + + if (hlID == HLF_CHD || hlID == HLF_TXD) + { + col = tv_get_number(&argvars[1]) - 1; // ignore type error in {col} + if (col >= change_start && col <= change_end) + hlID = HLF_TXD; // changed text + else + hlID = HLF_CHD; // changed line + } + rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID; +#endif +} + +#endif diff --git a/src/digraph.c b/src/digraph.c new file mode 100644 index 0000000..fb45c15 --- /dev/null +++ b/src/digraph.c @@ -0,0 +1,2408 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * digraph.c: code for digraphs + */ + +#include "vim.h" + +#if defined(FEAT_DIGRAPHS) || defined(PROTO) + +typedef int result_T; + +typedef struct digraph +{ + char_u char1; + char_u char2; + result_T result; +} digr_T; + +static void printdigraph(digr_T *dp, result_T *previous); + +// digraphs added by the user +static garray_T user_digraphs = {0, 0, (int)sizeof(digr_T), 10, NULL}; + +/* + * digraphs for Unicode from RFC1345 + * (also work for ISO-8859-1 aka latin1) + * + * Note: Characters marked with XX are not included literally, because some + * compilers cannot handle them (Amiga SAS/C is the most picky one). + */ +static digr_T digraphdefault[] = { + {'N', 'U', 0x0a}, // LF for NUL + {'S', 'H', 0x01}, + {'S', 'X', 0x02}, + {'E', 'X', 0x03}, + {'E', 'T', 0x04}, + {'E', 'Q', 0x05}, + {'A', 'K', 0x06}, + {'B', 'L', 0x07}, + {'B', 'S', 0x08}, + {'H', 'T', 0x09}, + {'L', 'F', 0x0a}, + {'V', 'T', 0x0b}, + {'F', 'F', 0x0c}, + {'C', 'R', 0x0d}, + {'S', 'O', 0x0e}, + {'S', 'I', 0x0f}, + {'D', 'L', 0x10}, + {'D', '1', 0x11}, + {'D', '2', 0x12}, + {'D', '3', 0x13}, + {'D', '4', 0x14}, + {'N', 'K', 0x15}, + {'S', 'Y', 0x16}, + {'E', 'B', 0x17}, + {'C', 'N', 0x18}, + {'E', 'M', 0x19}, + {'S', 'B', 0x1a}, + {'E', 'C', 0x1b}, + {'F', 'S', 0x1c}, + {'G', 'S', 0x1d}, + {'R', 'S', 0x1e}, + {'U', 'S', 0x1f}, + {'S', 'P', 0x20}, + {'N', 'b', 0x23}, + {'D', 'O', 0x24}, + {'A', 't', 0x40}, + {'<', '(', 0x5b}, + {'/', '/', 0x5c}, + {')', '>', 0x5d}, + {'\'', '>', 0x5e}, + {'\'', '!', 0x60}, + {'(', '!', 0x7b}, + {'!', '!', 0x7c}, + {'!', ')', 0x7d}, + {'\'', '?', 0x7e}, + {'D', 'T', 0x7f}, + {'P', 'A', 0x80}, + {'H', 'O', 0x81}, + {'B', 'H', 0x82}, + {'N', 'H', 0x83}, + {'I', 'N', 0x84}, + {'N', 'L', 0x85}, + {'S', 'A', 0x86}, + {'E', 'S', 0x87}, + {'H', 'S', 0x88}, + {'H', 'J', 0x89}, + {'V', 'S', 0x8a}, + {'P', 'D', 0x8b}, + {'P', 'U', 0x8c}, + {'R', 'I', 0x8d}, + {'S', '2', 0x8e}, + {'S', '3', 0x8f}, + {'D', 'C', 0x90}, + {'P', '1', 0x91}, + {'P', '2', 0x92}, + {'T', 'S', 0x93}, + {'C', 'C', 0x94}, + {'M', 'W', 0x95}, + {'S', 'G', 0x96}, + {'E', 'G', 0x97}, + {'S', 'S', 0x98}, + {'G', 'C', 0x99}, + {'S', 'C', 0x9a}, + {'C', 'I', 0x9b}, + {'S', 'T', 0x9c}, + {'O', 'C', 0x9d}, + {'P', 'M', 0x9e}, + {'A', 'C', 0x9f}, + {'N', 'S', 0xa0}, +# define DG_START_LATIN 0xa1 + {'!', 'I', 0xa1}, + {'~', '!', 0xa1}, // ¡ Vim 5.x compatible + {'C', 't', 0xa2}, + {'c', '|', 0xa2}, // ¢ Vim 5.x compatible + {'P', 'd', 0xa3}, + {'$', '$', 0xa3}, // £ Vim 5.x compatible + {'C', 'u', 0xa4}, + {'o', 'x', 0xa4}, // ¤ Vim 5.x compatible + {'Y', 'e', 0xa5}, + {'Y', '-', 0xa5}, // Â¥ Vim 5.x compatible + {'B', 'B', 0xa6}, + {'|', '|', 0xa6}, // ¦ Vim 5.x compatible + {'S', 'E', 0xa7}, + {'\'', ':', 0xa8}, + {'C', 'o', 0xa9}, + {'c', 'O', 0xa9}, // © Vim 5.x compatible + {'-', 'a', 0xaa}, + {'<', '<', 0xab}, + {'N', 'O', 0xac}, + {'-', ',', 0xac}, // ¬ Vim 5.x compatible + {'-', '-', 0xad}, + {'R', 'g', 0xae}, + {'\'', 'm', 0xaf}, + {'-', '=', 0xaf}, // ¯ Vim 5.x compatible + {'D', 'G', 0xb0}, + {'~', 'o', 0xb0}, // ° Vim 5.x compatible + {'+', '-', 0xb1}, + {'2', 'S', 0xb2}, + {'2', '2', 0xb2}, // ² Vim 5.x compatible + {'3', 'S', 0xb3}, + {'3', '3', 0xb3}, // ³ Vim 5.x compatible + {'\'', '\'', 0xb4}, + {'M', 'y', 0xb5}, + {'P', 'I', 0xb6}, + {'p', 'p', 0xb6}, // ¶ Vim 5.x compatible + {'.', 'M', 0xb7}, + {'~', '.', 0xb7}, // · Vim 5.x compatible + {'\'', ',', 0xb8}, + {'1', 'S', 0xb9}, + {'1', '1', 0xb9}, // ¹ Vim 5.x compatible + {'-', 'o', 0xba}, + {'>', '>', 0xbb}, + {'1', '4', 0xbc}, + {'1', '2', 0xbd}, + {'3', '4', 0xbe}, + {'?', 'I', 0xbf}, + {'~', '?', 0xbf}, // ¿ Vim 5.x compatible + {'A', '!', 0xc0}, + {'A', '`', 0xc0}, // À Vim 5.x compatible + {'A', '\'', 0xc1}, + {'A', '>', 0xc2}, + {'A', '^', 0xc2}, //  Vim 5.x compatible + {'A', '?', 0xc3}, + {'A', '~', 0xc3}, // à Vim 5.x compatible + {'A', ':', 0xc4}, + {'A', '"', 0xc4}, // Ä Vim 5.x compatible + {'A', 'A', 0xc5}, + {'A', '@', 0xc5}, // Ã… Vim 5.x compatible + {'A', 'E', 0xc6}, + {'C', ',', 0xc7}, + {'E', '!', 0xc8}, + {'E', '`', 0xc8}, // È Vim 5.x compatible + {'E', '\'', 0xc9}, + {'E', '>', 0xca}, + {'E', '^', 0xca}, // Ê Vim 5.x compatible + {'E', ':', 0xcb}, + {'E', '"', 0xcb}, // Ë Vim 5.x compatible + {'I', '!', 0xcc}, + {'I', '`', 0xcc}, // ÃŒ Vim 5.x compatible + {'I', '\'', 0xcd}, + {'I', '>', 0xce}, + {'I', '^', 0xce}, // ÃŽ Vim 5.x compatible + {'I', ':', 0xcf}, + {'I', '"', 0xcf}, // à Vim 5.x compatible + {'D', '-', 0xd0}, + {'N', '?', 0xd1}, + {'N', '~', 0xd1}, // Ñ Vim 5.x compatible + {'O', '!', 0xd2}, + {'O', '`', 0xd2}, // Ã’ Vim 5.x compatible + {'O', '\'', 0xd3}, + {'O', '>', 0xd4}, + {'O', '^', 0xd4}, // Ô Vim 5.x compatible + {'O', '?', 0xd5}, + {'O', '~', 0xd5}, // Õ Vim 5.x compatible + {'O', ':', 0xd6}, + {'*', 'X', 0xd7}, + {'/', '\\', 0xd7}, // × Vim 5.x compatible + {'O', '/', 0xd8}, + {'U', '!', 0xd9}, + {'U', '`', 0xd9}, // Ù Vim 5.x compatible + {'U', '\'', 0xda}, + {'U', '>', 0xdb}, + {'U', '^', 0xdb}, // Û Vim 5.x compatible + {'U', ':', 0xdc}, + {'Y', '\'', 0xdd}, + {'T', 'H', 0xde}, + {'I', 'p', 0xde}, // Þ Vim 5.x compatible + {'s', 's', 0xdf}, + {'a', '!', 0xe0}, + {'a', '`', 0xe0}, // à Vim 5.x compatible + {'a', '\'', 0xe1}, + {'a', '>', 0xe2}, + {'a', '^', 0xe2}, // â Vim 5.x compatible + {'a', '?', 0xe3}, + {'a', '~', 0xe3}, // ã Vim 5.x compatible + {'a', ':', 0xe4}, + {'a', '"', 0xe4}, // ä Vim 5.x compatible + {'a', 'a', 0xe5}, + {'a', '@', 0xe5}, // Ã¥ Vim 5.x compatible + {'a', 'e', 0xe6}, + {'c', ',', 0xe7}, + {'e', '!', 0xe8}, + {'e', '`', 0xe8}, // è Vim 5.x compatible + {'e', '\'', 0xe9}, + {'e', '>', 0xea}, + {'e', '^', 0xea}, // ê Vim 5.x compatible + {'e', ':', 0xeb}, + {'e', '"', 0xeb}, // ë Vim 5.x compatible + {'i', '!', 0xec}, + {'i', '`', 0xec}, // ì Vim 5.x compatible + {'i', '\'', 0xed}, + {'i', '>', 0xee}, + {'i', '^', 0xee}, // î Vim 5.x compatible + {'i', ':', 0xef}, + {'d', '-', 0xf0}, + {'n', '?', 0xf1}, + {'n', '~', 0xf1}, // ñ Vim 5.x compatible + {'o', '!', 0xf2}, + {'o', '`', 0xf2}, // ò Vim 5.x compatible + {'o', '\'', 0xf3}, + {'o', '>', 0xf4}, + {'o', '^', 0xf4}, // ô Vim 5.x compatible + {'o', '?', 0xf5}, + {'o', '~', 0xf5}, // õ Vim 5.x compatible + {'o', ':', 0xf6}, + {'-', ':', 0xf7}, + {'o', '/', 0xf8}, + {'u', '!', 0xf9}, + {'u', '`', 0xf9}, // ù Vim 5.x compatible + {'u', '\'', 0xfa}, + {'u', '>', 0xfb}, + {'u', '^', 0xfb}, // û Vim 5.x compatible + {'u', ':', 0xfc}, + {'y', '\'', 0xfd}, + {'t', 'h', 0xfe}, + {'y', ':', 0xff}, + {'y', '"', 0xff}, // x XX Vim 5.x compatible + +# define USE_UNICODE_DIGRAPHS + + {'A', '-', 0x0100}, + {'a', '-', 0x0101}, + {'A', '(', 0x0102}, + {'a', '(', 0x0103}, + {'A', ';', 0x0104}, + {'a', ';', 0x0105}, + {'C', '\'', 0x0106}, + {'c', '\'', 0x0107}, + {'C', '>', 0x0108}, + {'c', '>', 0x0109}, + {'C', '.', 0x010a}, + {'c', '.', 0x010b}, + {'C', '<', 0x010c}, + {'c', '<', 0x010d}, + {'D', '<', 0x010e}, + {'d', '<', 0x010f}, + {'D', '/', 0x0110}, + {'d', '/', 0x0111}, + {'E', '-', 0x0112}, + {'e', '-', 0x0113}, + {'E', '(', 0x0114}, + {'e', '(', 0x0115}, + {'E', '.', 0x0116}, + {'e', '.', 0x0117}, + {'E', ';', 0x0118}, + {'e', ';', 0x0119}, + {'E', '<', 0x011a}, + {'e', '<', 0x011b}, + {'G', '>', 0x011c}, + {'g', '>', 0x011d}, + {'G', '(', 0x011e}, + {'g', '(', 0x011f}, + {'G', '.', 0x0120}, + {'g', '.', 0x0121}, + {'G', ',', 0x0122}, + {'g', ',', 0x0123}, + {'H', '>', 0x0124}, + {'h', '>', 0x0125}, + {'H', '/', 0x0126}, + {'h', '/', 0x0127}, + {'I', '?', 0x0128}, + {'i', '?', 0x0129}, + {'I', '-', 0x012a}, + {'i', '-', 0x012b}, + {'I', '(', 0x012c}, + {'i', '(', 0x012d}, + {'I', ';', 0x012e}, + {'i', ';', 0x012f}, + {'I', '.', 0x0130}, + {'i', '.', 0x0131}, + {'I', 'J', 0x0132}, + {'i', 'j', 0x0133}, + {'J', '>', 0x0134}, + {'j', '>', 0x0135}, + {'K', ',', 0x0136}, + {'k', ',', 0x0137}, + {'k', 'k', 0x0138}, + {'L', '\'', 0x0139}, + {'l', '\'', 0x013a}, + {'L', ',', 0x013b}, + {'l', ',', 0x013c}, + {'L', '<', 0x013d}, + {'l', '<', 0x013e}, + {'L', '.', 0x013f}, + {'l', '.', 0x0140}, + {'L', '/', 0x0141}, + {'l', '/', 0x0142}, + {'N', '\'', 0x0143}, + {'n', '\'', 0x0144}, + {'N', ',', 0x0145}, + {'n', ',', 0x0146}, + {'N', '<', 0x0147}, + {'n', '<', 0x0148}, + {'\'', 'n', 0x0149}, + {'N', 'G', 0x014a}, + {'n', 'g', 0x014b}, + {'O', '-', 0x014c}, + {'o', '-', 0x014d}, + {'O', '(', 0x014e}, + {'o', '(', 0x014f}, + {'O', '"', 0x0150}, + {'o', '"', 0x0151}, + {'O', 'E', 0x0152}, + {'o', 'e', 0x0153}, + {'R', '\'', 0x0154}, + {'r', '\'', 0x0155}, + {'R', ',', 0x0156}, + {'r', ',', 0x0157}, + {'R', '<', 0x0158}, + {'r', '<', 0x0159}, + {'S', '\'', 0x015a}, + {'s', '\'', 0x015b}, + {'S', '>', 0x015c}, + {'s', '>', 0x015d}, + {'S', ',', 0x015e}, + {'s', ',', 0x015f}, + {'S', '<', 0x0160}, + {'s', '<', 0x0161}, + {'T', ',', 0x0162}, + {'t', ',', 0x0163}, + {'T', '<', 0x0164}, + {'t', '<', 0x0165}, + {'T', '/', 0x0166}, + {'t', '/', 0x0167}, + {'U', '?', 0x0168}, + {'u', '?', 0x0169}, + {'U', '-', 0x016a}, + {'u', '-', 0x016b}, + {'U', '(', 0x016c}, + {'u', '(', 0x016d}, + {'U', '0', 0x016e}, + {'u', '0', 0x016f}, + {'U', '"', 0x0170}, + {'u', '"', 0x0171}, + {'U', ';', 0x0172}, + {'u', ';', 0x0173}, + {'W', '>', 0x0174}, + {'w', '>', 0x0175}, + {'Y', '>', 0x0176}, + {'y', '>', 0x0177}, + {'Y', ':', 0x0178}, + {'Z', '\'', 0x0179}, + {'z', '\'', 0x017a}, + {'Z', '.', 0x017b}, + {'z', '.', 0x017c}, + {'Z', '<', 0x017d}, + {'z', '<', 0x017e}, + {'O', '9', 0x01a0}, + {'o', '9', 0x01a1}, + {'O', 'I', 0x01a2}, + {'o', 'i', 0x01a3}, + {'y', 'r', 0x01a6}, + {'U', '9', 0x01af}, + {'u', '9', 0x01b0}, + {'Z', '/', 0x01b5}, + {'z', '/', 0x01b6}, + {'E', 'D', 0x01b7}, + {'A', '<', 0x01cd}, + {'a', '<', 0x01ce}, + {'I', '<', 0x01cf}, + {'i', '<', 0x01d0}, + {'O', '<', 0x01d1}, + {'o', '<', 0x01d2}, + {'U', '<', 0x01d3}, + {'u', '<', 0x01d4}, + {'A', '1', 0x01de}, + {'a', '1', 0x01df}, + {'A', '7', 0x01e0}, + {'a', '7', 0x01e1}, + {'A', '3', 0x01e2}, + {'a', '3', 0x01e3}, + {'G', '/', 0x01e4}, + {'g', '/', 0x01e5}, + {'G', '<', 0x01e6}, + {'g', '<', 0x01e7}, + {'K', '<', 0x01e8}, + {'k', '<', 0x01e9}, + {'O', ';', 0x01ea}, + {'o', ';', 0x01eb}, + {'O', '1', 0x01ec}, + {'o', '1', 0x01ed}, + {'E', 'Z', 0x01ee}, + {'e', 'z', 0x01ef}, + {'j', '<', 0x01f0}, + {'G', '\'', 0x01f4}, + {'g', '\'', 0x01f5}, + {';', 'S', 0x02bf}, + {'\'', '<', 0x02c7}, + {'\'', '(', 0x02d8}, + {'\'', '.', 0x02d9}, + {'\'', '0', 0x02da}, + {'\'', ';', 0x02db}, + {'\'', '"', 0x02dd}, +# define DG_START_GREEK 0x0386 + {'A', '%', 0x0386}, + {'E', '%', 0x0388}, + {'Y', '%', 0x0389}, + {'I', '%', 0x038a}, + {'O', '%', 0x038c}, + {'U', '%', 0x038e}, + {'W', '%', 0x038f}, + {'i', '3', 0x0390}, + {'A', '*', 0x0391}, + {'B', '*', 0x0392}, + {'G', '*', 0x0393}, + {'D', '*', 0x0394}, + {'E', '*', 0x0395}, + {'Z', '*', 0x0396}, + {'Y', '*', 0x0397}, + {'H', '*', 0x0398}, + {'I', '*', 0x0399}, + {'K', '*', 0x039a}, + {'L', '*', 0x039b}, + {'M', '*', 0x039c}, + {'N', '*', 0x039d}, + {'C', '*', 0x039e}, + {'O', '*', 0x039f}, + {'P', '*', 0x03a0}, + {'R', '*', 0x03a1}, + {'S', '*', 0x03a3}, + {'T', '*', 0x03a4}, + {'U', '*', 0x03a5}, + {'F', '*', 0x03a6}, + {'X', '*', 0x03a7}, + {'Q', '*', 0x03a8}, + {'W', '*', 0x03a9}, + {'J', '*', 0x03aa}, + {'V', '*', 0x03ab}, + {'a', '%', 0x03ac}, + {'e', '%', 0x03ad}, + {'y', '%', 0x03ae}, + {'i', '%', 0x03af}, + {'u', '3', 0x03b0}, + {'a', '*', 0x03b1}, + {'b', '*', 0x03b2}, + {'g', '*', 0x03b3}, + {'d', '*', 0x03b4}, + {'e', '*', 0x03b5}, + {'z', '*', 0x03b6}, + {'y', '*', 0x03b7}, + {'h', '*', 0x03b8}, + {'i', '*', 0x03b9}, + {'k', '*', 0x03ba}, + {'l', '*', 0x03bb}, + {'m', '*', 0x03bc}, + {'n', '*', 0x03bd}, + {'c', '*', 0x03be}, + {'o', '*', 0x03bf}, + {'p', '*', 0x03c0}, + {'r', '*', 0x03c1}, + {'*', 's', 0x03c2}, + {'s', '*', 0x03c3}, + {'t', '*', 0x03c4}, + {'u', '*', 0x03c5}, + {'f', '*', 0x03c6}, + {'x', '*', 0x03c7}, + {'q', '*', 0x03c8}, + {'w', '*', 0x03c9}, + {'j', '*', 0x03ca}, + {'v', '*', 0x03cb}, + {'o', '%', 0x03cc}, + {'u', '%', 0x03cd}, + {'w', '%', 0x03ce}, + {'\'', 'G', 0x03d8}, + {',', 'G', 0x03d9}, + {'T', '3', 0x03da}, + {'t', '3', 0x03db}, + {'M', '3', 0x03dc}, + {'m', '3', 0x03dd}, + {'K', '3', 0x03de}, + {'k', '3', 0x03df}, + {'P', '3', 0x03e0}, + {'p', '3', 0x03e1}, + {'\'', '%', 0x03f4}, + {'j', '3', 0x03f5}, +# define DG_START_CYRILLIC 0x0401 + {'I', 'O', 0x0401}, + {'D', '%', 0x0402}, + {'G', '%', 0x0403}, + {'I', 'E', 0x0404}, + {'D', 'S', 0x0405}, + {'I', 'I', 0x0406}, + {'Y', 'I', 0x0407}, + {'J', '%', 0x0408}, + {'L', 'J', 0x0409}, + {'N', 'J', 0x040a}, + {'T', 's', 0x040b}, + {'K', 'J', 0x040c}, + {'V', '%', 0x040e}, + {'D', 'Z', 0x040f}, + {'A', '=', 0x0410}, + {'B', '=', 0x0411}, + {'V', '=', 0x0412}, + {'G', '=', 0x0413}, + {'D', '=', 0x0414}, + {'E', '=', 0x0415}, + {'Z', '%', 0x0416}, + {'Z', '=', 0x0417}, + {'I', '=', 0x0418}, + {'J', '=', 0x0419}, + {'K', '=', 0x041a}, + {'L', '=', 0x041b}, + {'M', '=', 0x041c}, + {'N', '=', 0x041d}, + {'O', '=', 0x041e}, + {'P', '=', 0x041f}, + {'R', '=', 0x0420}, + {'S', '=', 0x0421}, + {'T', '=', 0x0422}, + {'U', '=', 0x0423}, + {'F', '=', 0x0424}, + {'H', '=', 0x0425}, + {'C', '=', 0x0426}, + {'C', '%', 0x0427}, + {'S', '%', 0x0428}, + {'S', 'c', 0x0429}, + {'=', '"', 0x042a}, + {'Y', '=', 0x042b}, + {'%', '"', 0x042c}, + {'J', 'E', 0x042d}, + {'J', 'U', 0x042e}, + {'J', 'A', 0x042f}, + {'a', '=', 0x0430}, + {'b', '=', 0x0431}, + {'v', '=', 0x0432}, + {'g', '=', 0x0433}, + {'d', '=', 0x0434}, + {'e', '=', 0x0435}, + {'z', '%', 0x0436}, + {'z', '=', 0x0437}, + {'i', '=', 0x0438}, + {'j', '=', 0x0439}, + {'k', '=', 0x043a}, + {'l', '=', 0x043b}, + {'m', '=', 0x043c}, + {'n', '=', 0x043d}, + {'o', '=', 0x043e}, + {'p', '=', 0x043f}, + {'r', '=', 0x0440}, + {'s', '=', 0x0441}, + {'t', '=', 0x0442}, + {'u', '=', 0x0443}, + {'f', '=', 0x0444}, + {'h', '=', 0x0445}, + {'c', '=', 0x0446}, + {'c', '%', 0x0447}, + {'s', '%', 0x0448}, + {'s', 'c', 0x0449}, + {'=', '\'', 0x044a}, + {'y', '=', 0x044b}, + {'%', '\'', 0x044c}, + {'j', 'e', 0x044d}, + {'j', 'u', 0x044e}, + {'j', 'a', 0x044f}, + {'i', 'o', 0x0451}, + {'d', '%', 0x0452}, + {'g', '%', 0x0453}, + {'i', 'e', 0x0454}, + {'d', 's', 0x0455}, + {'i', 'i', 0x0456}, + {'y', 'i', 0x0457}, + {'j', '%', 0x0458}, + {'l', 'j', 0x0459}, + {'n', 'j', 0x045a}, + {'t', 's', 0x045b}, + {'k', 'j', 0x045c}, + {'v', '%', 0x045e}, + {'d', 'z', 0x045f}, + {'Y', '3', 0x0462}, + {'y', '3', 0x0463}, + {'O', '3', 0x046a}, + {'o', '3', 0x046b}, + {'F', '3', 0x0472}, + {'f', '3', 0x0473}, + {'V', '3', 0x0474}, + {'v', '3', 0x0475}, + {'C', '3', 0x0480}, + {'c', '3', 0x0481}, + {'G', '3', 0x0490}, + {'g', '3', 0x0491}, +# define DG_START_HEBREW 0x05d0 + {'A', '+', 0x05d0}, + {'B', '+', 0x05d1}, + {'G', '+', 0x05d2}, + {'D', '+', 0x05d3}, + {'H', '+', 0x05d4}, + {'W', '+', 0x05d5}, + {'Z', '+', 0x05d6}, + {'X', '+', 0x05d7}, + {'T', 'j', 0x05d8}, + {'J', '+', 0x05d9}, + {'K', '%', 0x05da}, + {'K', '+', 0x05db}, + {'L', '+', 0x05dc}, + {'M', '%', 0x05dd}, + {'M', '+', 0x05de}, + {'N', '%', 0x05df}, + {'N', '+', 0x05e0}, + {'S', '+', 0x05e1}, + {'E', '+', 0x05e2}, + {'P', '%', 0x05e3}, + {'P', '+', 0x05e4}, + {'Z', 'j', 0x05e5}, + {'Z', 'J', 0x05e6}, + {'Q', '+', 0x05e7}, + {'R', '+', 0x05e8}, + {'S', 'h', 0x05e9}, + {'T', '+', 0x05ea}, +# define DG_START_ARABIC 0x060c + {',', '+', 0x060c}, + {';', '+', 0x061b}, + {'?', '+', 0x061f}, + {'H', '\'', 0x0621}, + {'a', 'M', 0x0622}, + {'a', 'H', 0x0623}, + {'w', 'H', 0x0624}, + {'a', 'h', 0x0625}, + {'y', 'H', 0x0626}, + {'a', '+', 0x0627}, + {'b', '+', 0x0628}, + {'t', 'm', 0x0629}, + {'t', '+', 0x062a}, + {'t', 'k', 0x062b}, + {'g', '+', 0x062c}, + {'h', 'k', 0x062d}, + {'x', '+', 0x062e}, + {'d', '+', 0x062f}, + {'d', 'k', 0x0630}, + {'r', '+', 0x0631}, + {'z', '+', 0x0632}, + {'s', '+', 0x0633}, + {'s', 'n', 0x0634}, + {'c', '+', 0x0635}, + {'d', 'd', 0x0636}, + {'t', 'j', 0x0637}, + {'z', 'H', 0x0638}, + {'e', '+', 0x0639}, + {'i', '+', 0x063a}, + {'+', '+', 0x0640}, + {'f', '+', 0x0641}, + {'q', '+', 0x0642}, + {'k', '+', 0x0643}, + {'l', '+', 0x0644}, + {'m', '+', 0x0645}, + {'n', '+', 0x0646}, + {'h', '+', 0x0647}, + {'w', '+', 0x0648}, + {'j', '+', 0x0649}, + {'y', '+', 0x064a}, + {':', '+', 0x064b}, + {'"', '+', 0x064c}, + {'=', '+', 0x064d}, + {'/', '+', 0x064e}, + {'\'', '+', 0x064f}, + {'1', '+', 0x0650}, + {'3', '+', 0x0651}, + {'0', '+', 0x0652}, + {'a', 'S', 0x0670}, + {'p', '+', 0x067e}, + {'v', '+', 0x06a4}, + {'g', 'f', 0x06af}, + {'0', 'a', 0x06f0}, + {'1', 'a', 0x06f1}, + {'2', 'a', 0x06f2}, + {'3', 'a', 0x06f3}, + {'4', 'a', 0x06f4}, + {'5', 'a', 0x06f5}, + {'6', 'a', 0x06f6}, + {'7', 'a', 0x06f7}, + {'8', 'a', 0x06f8}, + {'9', 'a', 0x06f9}, +# define DG_START_LATIN_EXTENDED 0x1e02 + {'B', '.', 0x1e02}, + {'b', '.', 0x1e03}, + {'B', '_', 0x1e06}, + {'b', '_', 0x1e07}, + {'D', '.', 0x1e0a}, + {'d', '.', 0x1e0b}, + {'D', '_', 0x1e0e}, + {'d', '_', 0x1e0f}, + {'D', ',', 0x1e10}, + {'d', ',', 0x1e11}, + {'F', '.', 0x1e1e}, + {'f', '.', 0x1e1f}, + {'G', '-', 0x1e20}, + {'g', '-', 0x1e21}, + {'H', '.', 0x1e22}, + {'h', '.', 0x1e23}, + {'H', ':', 0x1e26}, + {'h', ':', 0x1e27}, + {'H', ',', 0x1e28}, + {'h', ',', 0x1e29}, + {'K', '\'', 0x1e30}, + {'k', '\'', 0x1e31}, + {'K', '_', 0x1e34}, + {'k', '_', 0x1e35}, + {'L', '_', 0x1e3a}, + {'l', '_', 0x1e3b}, + {'M', '\'', 0x1e3e}, + {'m', '\'', 0x1e3f}, + {'M', '.', 0x1e40}, + {'m', '.', 0x1e41}, + {'N', '.', 0x1e44}, + {'n', '.', 0x1e45}, + {'N', '_', 0x1e48}, + {'n', '_', 0x1e49}, + {'P', '\'', 0x1e54}, + {'p', '\'', 0x1e55}, + {'P', '.', 0x1e56}, + {'p', '.', 0x1e57}, + {'R', '.', 0x1e58}, + {'r', '.', 0x1e59}, + {'R', '_', 0x1e5e}, + {'r', '_', 0x1e5f}, + {'S', '.', 0x1e60}, + {'s', '.', 0x1e61}, + {'T', '.', 0x1e6a}, + {'t', '.', 0x1e6b}, + {'T', '_', 0x1e6e}, + {'t', '_', 0x1e6f}, + {'V', '?', 0x1e7c}, + {'v', '?', 0x1e7d}, + {'W', '!', 0x1e80}, + {'W', '`', 0x1e80}, // extra alternative, easier to remember + {'w', '!', 0x1e81}, + {'w', '`', 0x1e81}, // extra alternative, easier to remember + {'W', '\'', 0x1e82}, + {'w', '\'', 0x1e83}, + {'W', ':', 0x1e84}, + {'w', ':', 0x1e85}, + {'W', '.', 0x1e86}, + {'w', '.', 0x1e87}, + {'X', '.', 0x1e8a}, + {'x', '.', 0x1e8b}, + {'X', ':', 0x1e8c}, + {'x', ':', 0x1e8d}, + {'Y', '.', 0x1e8e}, + {'y', '.', 0x1e8f}, + {'Z', '>', 0x1e90}, + {'z', '>', 0x1e91}, + {'Z', '_', 0x1e94}, + {'z', '_', 0x1e95}, + {'h', '_', 0x1e96}, + {'t', ':', 0x1e97}, + {'w', '0', 0x1e98}, + {'y', '0', 0x1e99}, + {'A', '2', 0x1ea2}, + {'a', '2', 0x1ea3}, + {'E', '2', 0x1eba}, + {'e', '2', 0x1ebb}, + {'E', '?', 0x1ebc}, + {'e', '?', 0x1ebd}, + {'I', '2', 0x1ec8}, + {'i', '2', 0x1ec9}, + {'O', '2', 0x1ece}, + {'o', '2', 0x1ecf}, + {'U', '2', 0x1ee6}, + {'u', '2', 0x1ee7}, + {'Y', '!', 0x1ef2}, + {'Y', '`', 0x1ef2}, // extra alternative, easier to remember + {'y', '!', 0x1ef3}, + {'y', '`', 0x1ef3}, // extra alternative, easier to remember + {'Y', '2', 0x1ef6}, + {'y', '2', 0x1ef7}, + {'Y', '?', 0x1ef8}, + {'y', '?', 0x1ef9}, +# define DG_START_GREEK_EXTENDED 0x1f00 + {';', '\'', 0x1f00}, + {',', '\'', 0x1f01}, + {';', '!', 0x1f02}, + {',', '!', 0x1f03}, + {'?', ';', 0x1f04}, + {'?', ',', 0x1f05}, + {'!', ':', 0x1f06}, + {'?', ':', 0x1f07}, +# define DG_START_PUNCTUATION 0x2002 + {'1', 'N', 0x2002}, + {'1', 'M', 0x2003}, + {'3', 'M', 0x2004}, + {'4', 'M', 0x2005}, + {'6', 'M', 0x2006}, + {'1', 'T', 0x2009}, + {'1', 'H', 0x200a}, + {'-', '1', 0x2010}, + {'-', 'N', 0x2013}, + {'-', 'M', 0x2014}, + {'-', '3', 0x2015}, + {'!', '2', 0x2016}, + {'=', '2', 0x2017}, + {'\'', '6', 0x2018}, + {'\'', '9', 0x2019}, + {'.', '9', 0x201a}, + {'9', '\'', 0x201b}, + {'"', '6', 0x201c}, + {'"', '9', 0x201d}, + {':', '9', 0x201e}, + {'9', '"', 0x201f}, + {'/', '-', 0x2020}, + {'/', '=', 0x2021}, + {'o', 'o', 0x2022}, + {'.', '.', 0x2025}, + {',', '.', 0x2026}, + {'%', '0', 0x2030}, + {'1', '\'', 0x2032}, + {'2', '\'', 0x2033}, + {'3', '\'', 0x2034}, + {'1', '"', 0x2035}, + {'2', '"', 0x2036}, + {'3', '"', 0x2037}, + {'C', 'a', 0x2038}, + {'<', '1', 0x2039}, + {'>', '1', 0x203a}, + {':', 'X', 0x203b}, + {'\'', '-', 0x203e}, + {'/', 'f', 0x2044}, +# define DG_START_SUB_SUPER 0x2070 + {'0', 'S', 0x2070}, + {'4', 'S', 0x2074}, + {'5', 'S', 0x2075}, + {'6', 'S', 0x2076}, + {'7', 'S', 0x2077}, + {'8', 'S', 0x2078}, + {'9', 'S', 0x2079}, + {'+', 'S', 0x207a}, + {'-', 'S', 0x207b}, + {'=', 'S', 0x207c}, + {'(', 'S', 0x207d}, + {')', 'S', 0x207e}, + {'n', 'S', 0x207f}, + {'0', 's', 0x2080}, + {'1', 's', 0x2081}, + {'2', 's', 0x2082}, + {'3', 's', 0x2083}, + {'4', 's', 0x2084}, + {'5', 's', 0x2085}, + {'6', 's', 0x2086}, + {'7', 's', 0x2087}, + {'8', 's', 0x2088}, + {'9', 's', 0x2089}, + {'+', 's', 0x208a}, + {'-', 's', 0x208b}, + {'=', 's', 0x208c}, + {'(', 's', 0x208d}, + {')', 's', 0x208e}, +# define DG_START_CURRENCY 0x20a4 + {'L', 'i', 0x20a4}, + {'P', 't', 0x20a7}, + {'W', '=', 0x20a9}, + {'=', 'e', 0x20ac}, // euro + {'E', 'u', 0x20ac}, // euro + {'=', 'R', 0x20bd}, // rouble + {'=', 'P', 0x20bd}, // rouble +# define DG_START_OTHER1 0x2103 + {'o', 'C', 0x2103}, + {'c', 'o', 0x2105}, + {'o', 'F', 0x2109}, + {'N', '0', 0x2116}, + {'P', 'O', 0x2117}, + {'R', 'x', 0x211e}, + {'S', 'M', 0x2120}, + {'T', 'M', 0x2122}, + {'O', 'm', 0x2126}, + {'A', 'O', 0x212b}, + {'1', '3', 0x2153}, + {'2', '3', 0x2154}, + {'1', '5', 0x2155}, + {'2', '5', 0x2156}, + {'3', '5', 0x2157}, + {'4', '5', 0x2158}, + {'1', '6', 0x2159}, + {'5', '6', 0x215a}, + {'1', '8', 0x215b}, + {'3', '8', 0x215c}, + {'5', '8', 0x215d}, + {'7', '8', 0x215e}, +# define DG_START_ROMAN 0x2160 + {'1', 'R', 0x2160}, + {'2', 'R', 0x2161}, + {'3', 'R', 0x2162}, + {'4', 'R', 0x2163}, + {'5', 'R', 0x2164}, + {'6', 'R', 0x2165}, + {'7', 'R', 0x2166}, + {'8', 'R', 0x2167}, + {'9', 'R', 0x2168}, + {'a', 'R', 0x2169}, + {'b', 'R', 0x216a}, + {'c', 'R', 0x216b}, + {'1', 'r', 0x2170}, + {'2', 'r', 0x2171}, + {'3', 'r', 0x2172}, + {'4', 'r', 0x2173}, + {'5', 'r', 0x2174}, + {'6', 'r', 0x2175}, + {'7', 'r', 0x2176}, + {'8', 'r', 0x2177}, + {'9', 'r', 0x2178}, + {'a', 'r', 0x2179}, + {'b', 'r', 0x217a}, + {'c', 'r', 0x217b}, +# define DG_START_ARROWS 0x2190 + {'<', '-', 0x2190}, + {'-', '!', 0x2191}, + {'-', '>', 0x2192}, + {'-', 'v', 0x2193}, + {'<', '>', 0x2194}, + {'U', 'D', 0x2195}, + {'<', '=', 0x21d0}, + {'=', '>', 0x21d2}, + {'=', '=', 0x21d4}, +# define DG_START_MATH 0x2200 + {'F', 'A', 0x2200}, + {'d', 'P', 0x2202}, + {'T', 'E', 0x2203}, + {'/', '0', 0x2205}, + {'D', 'E', 0x2206}, + {'N', 'B', 0x2207}, + {'(', '-', 0x2208}, + {'-', ')', 0x220b}, + {'*', 'P', 0x220f}, + {'+', 'Z', 0x2211}, + {'-', '2', 0x2212}, + {'-', '+', 0x2213}, + {'*', '-', 0x2217}, + {'O', 'b', 0x2218}, + {'S', 'b', 0x2219}, + {'R', 'T', 0x221a}, + {'0', '(', 0x221d}, + {'0', '0', 0x221e}, + {'-', 'L', 0x221f}, + {'-', 'V', 0x2220}, + {'P', 'P', 0x2225}, + {'A', 'N', 0x2227}, + {'O', 'R', 0x2228}, + {'(', 'U', 0x2229}, + {')', 'U', 0x222a}, + {'I', 'n', 0x222b}, + {'D', 'I', 0x222c}, + {'I', 'o', 0x222e}, + {'.', ':', 0x2234}, + {':', '.', 0x2235}, + {':', 'R', 0x2236}, + {':', ':', 0x2237}, + {'?', '1', 0x223c}, + {'C', 'G', 0x223e}, + {'?', '-', 0x2243}, + {'?', '=', 0x2245}, + {'?', '2', 0x2248}, + {'=', '?', 0x224c}, + {'H', 'I', 0x2253}, + {'!', '=', 0x2260}, + {'=', '3', 0x2261}, + {'=', '<', 0x2264}, + {'>', '=', 0x2265}, + {'<', '*', 0x226a}, + {'*', '>', 0x226b}, + {'!', '<', 0x226e}, + {'!', '>', 0x226f}, + {'(', 'C', 0x2282}, + {')', 'C', 0x2283}, + {'(', '_', 0x2286}, + {')', '_', 0x2287}, + {'0', '.', 0x2299}, + {'0', '2', 0x229a}, + {'-', 'T', 0x22a5}, + {'.', 'P', 0x22c5}, + {':', '3', 0x22ee}, + {'.', '3', 0x22ef}, +# define DG_START_TECHNICAL 0x2302 + {'E', 'h', 0x2302}, + {'<', '7', 0x2308}, + {'>', '7', 0x2309}, + {'7', '<', 0x230a}, + {'7', '>', 0x230b}, + {'N', 'I', 0x2310}, + {'(', 'A', 0x2312}, + {'T', 'R', 0x2315}, + {'I', 'u', 0x2320}, + {'I', 'l', 0x2321}, + {'<', '/', 0x2329}, + {'/', '>', 0x232a}, +# define DG_START_OTHER2 0x2423 + {'V', 's', 0x2423}, + {'1', 'h', 0x2440}, + {'3', 'h', 0x2441}, + {'2', 'h', 0x2442}, + {'4', 'h', 0x2443}, + {'1', 'j', 0x2446}, + {'2', 'j', 0x2447}, + {'3', 'j', 0x2448}, + {'4', 'j', 0x2449}, + {'1', '.', 0x2488}, + {'2', '.', 0x2489}, + {'3', '.', 0x248a}, + {'4', '.', 0x248b}, + {'5', '.', 0x248c}, + {'6', '.', 0x248d}, + {'7', '.', 0x248e}, + {'8', '.', 0x248f}, + {'9', '.', 0x2490}, +# define DG_START_DRAWING 0x2500 + {'h', 'h', 0x2500}, + {'H', 'H', 0x2501}, + {'v', 'v', 0x2502}, + {'V', 'V', 0x2503}, + {'3', '-', 0x2504}, + {'3', '_', 0x2505}, + {'3', '!', 0x2506}, + {'3', '/', 0x2507}, + {'4', '-', 0x2508}, + {'4', '_', 0x2509}, + {'4', '!', 0x250a}, + {'4', '/', 0x250b}, + {'d', 'r', 0x250c}, + {'d', 'R', 0x250d}, + {'D', 'r', 0x250e}, + {'D', 'R', 0x250f}, + {'d', 'l', 0x2510}, + {'d', 'L', 0x2511}, + {'D', 'l', 0x2512}, + {'L', 'D', 0x2513}, + {'u', 'r', 0x2514}, + {'u', 'R', 0x2515}, + {'U', 'r', 0x2516}, + {'U', 'R', 0x2517}, + {'u', 'l', 0x2518}, + {'u', 'L', 0x2519}, + {'U', 'l', 0x251a}, + {'U', 'L', 0x251b}, + {'v', 'r', 0x251c}, + {'v', 'R', 0x251d}, + {'V', 'r', 0x2520}, + {'V', 'R', 0x2523}, + {'v', 'l', 0x2524}, + {'v', 'L', 0x2525}, + {'V', 'l', 0x2528}, + {'V', 'L', 0x252b}, + {'d', 'h', 0x252c}, + {'d', 'H', 0x252f}, + {'D', 'h', 0x2530}, + {'D', 'H', 0x2533}, + {'u', 'h', 0x2534}, + {'u', 'H', 0x2537}, + {'U', 'h', 0x2538}, + {'U', 'H', 0x253b}, + {'v', 'h', 0x253c}, + {'v', 'H', 0x253f}, + {'V', 'h', 0x2542}, + {'V', 'H', 0x254b}, + {'F', 'D', 0x2571}, + {'B', 'D', 0x2572}, +# define DG_START_BLOCK 0x2580 + {'T', 'B', 0x2580}, + {'L', 'B', 0x2584}, + {'F', 'B', 0x2588}, + {'l', 'B', 0x258c}, + {'R', 'B', 0x2590}, + {'.', 'S', 0x2591}, + {':', 'S', 0x2592}, + {'?', 'S', 0x2593}, +# define DG_START_SHAPES 0x25a0 + {'f', 'S', 0x25a0}, + {'O', 'S', 0x25a1}, + {'R', 'O', 0x25a2}, + {'R', 'r', 0x25a3}, + {'R', 'F', 0x25a4}, + {'R', 'Y', 0x25a5}, + {'R', 'H', 0x25a6}, + {'R', 'Z', 0x25a7}, + {'R', 'K', 0x25a8}, + {'R', 'X', 0x25a9}, + {'s', 'B', 0x25aa}, + {'S', 'R', 0x25ac}, + {'O', 'r', 0x25ad}, + {'U', 'T', 0x25b2}, + {'u', 'T', 0x25b3}, + {'P', 'R', 0x25b6}, + {'T', 'r', 0x25b7}, + {'D', 't', 0x25bc}, + {'d', 'T', 0x25bd}, + {'P', 'L', 0x25c0}, + {'T', 'l', 0x25c1}, + {'D', 'b', 0x25c6}, + {'D', 'w', 0x25c7}, + {'L', 'Z', 0x25ca}, + {'0', 'm', 0x25cb}, + {'0', 'o', 0x25ce}, + {'0', 'M', 0x25cf}, + {'0', 'L', 0x25d0}, + {'0', 'R', 0x25d1}, + {'S', 'n', 0x25d8}, + {'I', 'c', 0x25d9}, + {'F', 'd', 0x25e2}, + {'B', 'd', 0x25e3}, +# define DG_START_SYMBOLS 0x2605 + {'*', '2', 0x2605}, + {'*', '1', 0x2606}, + {'<', 'H', 0x261c}, + {'>', 'H', 0x261e}, + {'0', 'u', 0x263a}, + {'0', 'U', 0x263b}, + {'S', 'U', 0x263c}, + {'F', 'm', 0x2640}, + {'M', 'l', 0x2642}, + {'c', 'S', 0x2660}, + {'c', 'H', 0x2661}, + {'c', 'D', 0x2662}, + {'c', 'C', 0x2663}, + {'M', 'd', 0x2669}, + {'M', '8', 0x266a}, + {'M', '2', 0x266b}, + {'M', 'b', 0x266d}, + {'M', 'x', 0x266e}, + {'M', 'X', 0x266f}, +# define DG_START_DINGBATS 0x2713 + {'O', 'K', 0x2713}, + {'X', 'X', 0x2717}, + {'-', 'X', 0x2720}, +# define DG_START_CJK_SYMBOLS 0x3000 + {'I', 'S', 0x3000}, + {',', '_', 0x3001}, + {'.', '_', 0x3002}, + {'+', '"', 0x3003}, + {'+', '_', 0x3004}, + {'*', '_', 0x3005}, + {';', '_', 0x3006}, + {'0', '_', 0x3007}, + {'<', '+', 0x300a}, + {'>', '+', 0x300b}, + {'<', '\'', 0x300c}, + {'>', '\'', 0x300d}, + {'<', '"', 0x300e}, + {'>', '"', 0x300f}, + {'(', '"', 0x3010}, + {')', '"', 0x3011}, + {'=', 'T', 0x3012}, + {'=', '_', 0x3013}, + {'(', '\'', 0x3014}, + {')', '\'', 0x3015}, + {'(', 'I', 0x3016}, + {')', 'I', 0x3017}, + {'-', '?', 0x301c}, +# define DG_START_HIRAGANA 0x3041 + {'A', '5', 0x3041}, + {'a', '5', 0x3042}, + {'I', '5', 0x3043}, + {'i', '5', 0x3044}, + {'U', '5', 0x3045}, + {'u', '5', 0x3046}, + {'E', '5', 0x3047}, + {'e', '5', 0x3048}, + {'O', '5', 0x3049}, + {'o', '5', 0x304a}, + {'k', 'a', 0x304b}, + {'g', 'a', 0x304c}, + {'k', 'i', 0x304d}, + {'g', 'i', 0x304e}, + {'k', 'u', 0x304f}, + {'g', 'u', 0x3050}, + {'k', 'e', 0x3051}, + {'g', 'e', 0x3052}, + {'k', 'o', 0x3053}, + {'g', 'o', 0x3054}, + {'s', 'a', 0x3055}, + {'z', 'a', 0x3056}, + {'s', 'i', 0x3057}, + {'z', 'i', 0x3058}, + {'s', 'u', 0x3059}, + {'z', 'u', 0x305a}, + {'s', 'e', 0x305b}, + {'z', 'e', 0x305c}, + {'s', 'o', 0x305d}, + {'z', 'o', 0x305e}, + {'t', 'a', 0x305f}, + {'d', 'a', 0x3060}, + {'t', 'i', 0x3061}, + {'d', 'i', 0x3062}, + {'t', 'U', 0x3063}, + {'t', 'u', 0x3064}, + {'d', 'u', 0x3065}, + {'t', 'e', 0x3066}, + {'d', 'e', 0x3067}, + {'t', 'o', 0x3068}, + {'d', 'o', 0x3069}, + {'n', 'a', 0x306a}, + {'n', 'i', 0x306b}, + {'n', 'u', 0x306c}, + {'n', 'e', 0x306d}, + {'n', 'o', 0x306e}, + {'h', 'a', 0x306f}, + {'b', 'a', 0x3070}, + {'p', 'a', 0x3071}, + {'h', 'i', 0x3072}, + {'b', 'i', 0x3073}, + {'p', 'i', 0x3074}, + {'h', 'u', 0x3075}, + {'b', 'u', 0x3076}, + {'p', 'u', 0x3077}, + {'h', 'e', 0x3078}, + {'b', 'e', 0x3079}, + {'p', 'e', 0x307a}, + {'h', 'o', 0x307b}, + {'b', 'o', 0x307c}, + {'p', 'o', 0x307d}, + {'m', 'a', 0x307e}, + {'m', 'i', 0x307f}, + {'m', 'u', 0x3080}, + {'m', 'e', 0x3081}, + {'m', 'o', 0x3082}, + {'y', 'A', 0x3083}, + {'y', 'a', 0x3084}, + {'y', 'U', 0x3085}, + {'y', 'u', 0x3086}, + {'y', 'O', 0x3087}, + {'y', 'o', 0x3088}, + {'r', 'a', 0x3089}, + {'r', 'i', 0x308a}, + {'r', 'u', 0x308b}, + {'r', 'e', 0x308c}, + {'r', 'o', 0x308d}, + {'w', 'A', 0x308e}, + {'w', 'a', 0x308f}, + {'w', 'i', 0x3090}, + {'w', 'e', 0x3091}, + {'w', 'o', 0x3092}, + {'n', '5', 0x3093}, + {'v', 'u', 0x3094}, + {'"', '5', 0x309b}, + {'0', '5', 0x309c}, + {'*', '5', 0x309d}, + {'+', '5', 0x309e}, +# define DG_START_KATAKANA 0x30a1 + {'a', '6', 0x30a1}, + {'A', '6', 0x30a2}, + {'i', '6', 0x30a3}, + {'I', '6', 0x30a4}, + {'u', '6', 0x30a5}, + {'U', '6', 0x30a6}, + {'e', '6', 0x30a7}, + {'E', '6', 0x30a8}, + {'o', '6', 0x30a9}, + {'O', '6', 0x30aa}, + {'K', 'a', 0x30ab}, + {'G', 'a', 0x30ac}, + {'K', 'i', 0x30ad}, + {'G', 'i', 0x30ae}, + {'K', 'u', 0x30af}, + {'G', 'u', 0x30b0}, + {'K', 'e', 0x30b1}, + {'G', 'e', 0x30b2}, + {'K', 'o', 0x30b3}, + {'G', 'o', 0x30b4}, + {'S', 'a', 0x30b5}, + {'Z', 'a', 0x30b6}, + {'S', 'i', 0x30b7}, + {'Z', 'i', 0x30b8}, + {'S', 'u', 0x30b9}, + {'Z', 'u', 0x30ba}, + {'S', 'e', 0x30bb}, + {'Z', 'e', 0x30bc}, + {'S', 'o', 0x30bd}, + {'Z', 'o', 0x30be}, + {'T', 'a', 0x30bf}, + {'D', 'a', 0x30c0}, + {'T', 'i', 0x30c1}, + {'D', 'i', 0x30c2}, + {'T', 'U', 0x30c3}, + {'T', 'u', 0x30c4}, + {'D', 'u', 0x30c5}, + {'T', 'e', 0x30c6}, + {'D', 'e', 0x30c7}, + {'T', 'o', 0x30c8}, + {'D', 'o', 0x30c9}, + {'N', 'a', 0x30ca}, + {'N', 'i', 0x30cb}, + {'N', 'u', 0x30cc}, + {'N', 'e', 0x30cd}, + {'N', 'o', 0x30ce}, + {'H', 'a', 0x30cf}, + {'B', 'a', 0x30d0}, + {'P', 'a', 0x30d1}, + {'H', 'i', 0x30d2}, + {'B', 'i', 0x30d3}, + {'P', 'i', 0x30d4}, + {'H', 'u', 0x30d5}, + {'B', 'u', 0x30d6}, + {'P', 'u', 0x30d7}, + {'H', 'e', 0x30d8}, + {'B', 'e', 0x30d9}, + {'P', 'e', 0x30da}, + {'H', 'o', 0x30db}, + {'B', 'o', 0x30dc}, + {'P', 'o', 0x30dd}, + {'M', 'a', 0x30de}, + {'M', 'i', 0x30df}, + {'M', 'u', 0x30e0}, + {'M', 'e', 0x30e1}, + {'M', 'o', 0x30e2}, + {'Y', 'A', 0x30e3}, + {'Y', 'a', 0x30e4}, + {'Y', 'U', 0x30e5}, + {'Y', 'u', 0x30e6}, + {'Y', 'O', 0x30e7}, + {'Y', 'o', 0x30e8}, + {'R', 'a', 0x30e9}, + {'R', 'i', 0x30ea}, + {'R', 'u', 0x30eb}, + {'R', 'e', 0x30ec}, + {'R', 'o', 0x30ed}, + {'W', 'A', 0x30ee}, + {'W', 'a', 0x30ef}, + {'W', 'i', 0x30f0}, + {'W', 'e', 0x30f1}, + {'W', 'o', 0x30f2}, + {'N', '6', 0x30f3}, + {'V', 'u', 0x30f4}, + {'K', 'A', 0x30f5}, + {'K', 'E', 0x30f6}, + {'V', 'a', 0x30f7}, + {'V', 'i', 0x30f8}, + {'V', 'e', 0x30f9}, + {'V', 'o', 0x30fa}, + {'.', '6', 0x30fb}, + {'-', '6', 0x30fc}, + {'*', '6', 0x30fd}, + {'+', '6', 0x30fe}, +# define DG_START_BOPOMOFO 0x3105 + {'b', '4', 0x3105}, + {'p', '4', 0x3106}, + {'m', '4', 0x3107}, + {'f', '4', 0x3108}, + {'d', '4', 0x3109}, + {'t', '4', 0x310a}, + {'n', '4', 0x310b}, + {'l', '4', 0x310c}, + {'g', '4', 0x310d}, + {'k', '4', 0x310e}, + {'h', '4', 0x310f}, + {'j', '4', 0x3110}, + {'q', '4', 0x3111}, + {'x', '4', 0x3112}, + {'z', 'h', 0x3113}, + {'c', 'h', 0x3114}, + {'s', 'h', 0x3115}, + {'r', '4', 0x3116}, + {'z', '4', 0x3117}, + {'c', '4', 0x3118}, + {'s', '4', 0x3119}, + {'a', '4', 0x311a}, + {'o', '4', 0x311b}, + {'e', '4', 0x311c}, + {'a', 'i', 0x311e}, + {'e', 'i', 0x311f}, + {'a', 'u', 0x3120}, + {'o', 'u', 0x3121}, + {'a', 'n', 0x3122}, + {'e', 'n', 0x3123}, + {'a', 'N', 0x3124}, + {'e', 'N', 0x3125}, + {'e', 'r', 0x3126}, + {'i', '4', 0x3127}, + {'u', '4', 0x3128}, + {'i', 'u', 0x3129}, + {'v', '4', 0x312a}, + {'n', 'G', 0x312b}, + {'g', 'n', 0x312c}, +# define DG_START_OTHER3 0x3220 + {'1', 'c', 0x3220}, + {'2', 'c', 0x3221}, + {'3', 'c', 0x3222}, + {'4', 'c', 0x3223}, + {'5', 'c', 0x3224}, + {'6', 'c', 0x3225}, + {'7', 'c', 0x3226}, + {'8', 'c', 0x3227}, + {'9', 'c', 0x3228}, + // code points 0xe000 - 0xefff excluded, they have no assigned + // characters, only used in proposals. + {'f', 'f', 0xfb00}, + {'f', 'i', 0xfb01}, + {'f', 'l', 0xfb02}, + {'f', 't', 0xfb05}, + {'s', 't', 0xfb06}, + + {NUL, NUL, NUL} // end marker +}; + +/* + * handle digraphs after typing a character + */ + int +do_digraph(int c) +{ + static int backspaced; // character before K_BS + static int lastchar; // last typed character + + if (c == -1) // init values + { + backspaced = -1; + } + else if (p_dg) + { + if (backspaced >= 0) + c = digraph_get(backspaced, c, FALSE); + backspaced = -1; + if ((c == K_BS || c == Ctrl_H) && lastchar >= 0) + backspaced = lastchar; + } + lastchar = c; + return c; +} + +/* + * Find a digraph for "val". If found return the string to display it. + * If not found return NULL. + */ + char_u * +get_digraph_for_char(int val_arg) +{ + int val = val_arg; + int i; + int use_defaults; + digr_T *dp; + static char_u r[3]; + +#if defined(USE_UNICODE_DIGRAPHS) + if (!enc_utf8) + { + char_u buf[6], *to; + vimconv_T vc; + + // convert the character from 'encoding' to Unicode + i = mb_char2bytes(val, buf); + vc.vc_type = CONV_NONE; + if (convert_setup(&vc, p_enc, (char_u *)"utf-8") == OK) + { + vc.vc_fail = TRUE; + to = string_convert(&vc, buf, &i); + if (to != NULL) + { + val = utf_ptr2char(to); + vim_free(to); + } + (void)convert_setup(&vc, NULL, NULL); + } + } +#endif + + for (use_defaults = 0; use_defaults <= 1; use_defaults++) + { + if (use_defaults == 0) + dp = (digr_T *)user_digraphs.ga_data; + else + dp = digraphdefault; + for (i = 0; use_defaults ? dp->char1 != NUL + : i < user_digraphs.ga_len; ++i) + { + if (dp->result == val) + { + r[0] = dp->char1; + r[1] = dp->char2; + r[2] = NUL; + return r; + } + ++dp; + } + } + return NULL; +} + +/* + * Get a digraph. Used after typing CTRL-K on the command line or in normal + * mode. + * Returns composed character, or NUL when ESC was used. + */ + int +get_digraph( + int cmdline) // TRUE when called from the cmdline +{ + int c, cc; + + ++no_mapping; + ++allow_keys; + c = plain_vgetc(); + --no_mapping; + --allow_keys; + + if (c == ESC) // ESC cancels CTRL-K + return NUL; + + if (IS_SPECIAL(c)) // insert special key code + return c; + if (cmdline) + { + if (char2cells(c) == 1 +#if defined(FEAT_CRYPT) || defined(FEAT_EVAL) + && cmdline_star == 0 +#endif + ) + putcmdline(c, TRUE); + } + else + add_to_showcmd(c); + ++no_mapping; + ++allow_keys; + cc = plain_vgetc(); + --no_mapping; + --allow_keys; + if (cc != ESC) // ESC cancels CTRL-K + return digraph_get(c, cc, TRUE); + return NUL; +} + +/* + * Lookup the pair "char1", "char2" in the digraph tables. + * If no match, return "char2". + * If "meta_char" is TRUE and "char1" is a space, return "char2" | 0x80. + */ + static int +getexactdigraph(int char1, int char2, int meta_char) +{ + int i; + int retval = 0; + digr_T *dp; + + if (IS_SPECIAL(char1) || IS_SPECIAL(char2)) + return char2; + + /* + * Search user digraphs first. + */ + dp = (digr_T *)user_digraphs.ga_data; + for (i = 0; i < user_digraphs.ga_len; ++i) + { + if ((int)dp->char1 == char1 && (int)dp->char2 == char2) + { + retval = dp->result; + break; + } + ++dp; + } + + /* + * Search default digraphs. + */ + if (retval == 0) + { + dp = digraphdefault; + while (dp->char1 != 0) + { + if ((int)dp->char1 == char1 && (int)dp->char2 == char2) + { + retval = dp->result; + break; + } + ++dp; + } + } +#ifdef USE_UNICODE_DIGRAPHS + if (retval != 0 && !enc_utf8) + { + char_u buf[6], *to; + vimconv_T vc; + + /* + * Convert the Unicode digraph to 'encoding'. + */ + i = utf_char2bytes(retval, buf); + retval = 0; + vc.vc_type = CONV_NONE; + if (convert_setup(&vc, (char_u *)"utf-8", p_enc) == OK) + { + vc.vc_fail = TRUE; + to = string_convert(&vc, buf, &i); + if (to != NULL) + { + retval = (*mb_ptr2char)(to); + vim_free(to); + } + (void)convert_setup(&vc, NULL, NULL); + } + } +#endif + + // Ignore multi-byte characters when not in multi-byte mode. + if (!has_mbyte && retval > 0xff) + retval = 0; + + if (retval == 0) // digraph deleted or not found + { + if (char1 == ' ' && meta_char) // --> meta-char + return (char2 | 0x80); + return char2; + } + return retval; +} + +/* + * Get digraph. + * Allow for both char1-char2 and char2-char1 + */ + int +digraph_get(int char1, int char2, int meta_char) +{ + int retval; + + if (((retval = getexactdigraph(char1, char2, meta_char)) == char2) + && (char1 != char2) + && ((retval = getexactdigraph(char2, char1, meta_char)) == char1)) + return char2; + return retval; +} + +/* + * Add a digraph to the digraph table. + */ + static void +registerdigraph(int char1, int char2, int n) +{ + int i; + digr_T *dp; + + // If the digraph already exists, replace "result". + dp = (digr_T *)user_digraphs.ga_data; + for (i = 0; i < user_digraphs.ga_len; ++i) + { + if ((int)dp->char1 == char1 && (int)dp->char2 == char2) + { + dp->result = n; + return; + } + ++dp; + } + + // Add a new digraph to the table. + if (ga_grow(&user_digraphs, 1) == FAIL) + return; + + dp = (digr_T *)user_digraphs.ga_data + user_digraphs.ga_len; + dp->char1 = char1; + dp->char2 = char2; + dp->result = n; + ++user_digraphs.ga_len; +} + +/* + * Check the characters are valid for a digraph. + * If they are valid, returns TRUE; otherwise, give an error message and + * returns FALSE. + */ + static int +check_digraph_chars_valid(int char1, int char2) +{ + if (char2 == 0) + { + char_u msg[MB_MAXBYTES + 1]; + + msg[mb_char2bytes(char1, msg)] = NUL; + + semsg(_(e_digraph_must_be_just_two_characters_str), msg); + return FALSE; + } + if (char1 == ESC || char2 == ESC) + { + emsg(_(e_escape_not_allowed_in_digraph)); + return FALSE; + } + return TRUE; +} + + + +/* + * Add the digraphs in the argument to the digraph table. + * format: {c1}{c2} char {c1}{c2} char ... + */ + void +putdigraph(char_u *str) +{ + int char1, char2, n; + + while (*str != NUL) + { + str = skipwhite(str); + if (*str == NUL) + return; + char1 = *str++; + char2 = *str++; + + if (!check_digraph_chars_valid(char1, char2)) + return; + + str = skipwhite(str); + if (!VIM_ISDIGIT(*str)) + { + emsg(_(e_number_expected)); + return; + } + n = getdigits(&str); + + registerdigraph(char1, char2, n); + } +} + +#if defined(USE_UNICODE_DIGRAPHS) + static void +digraph_header(char *msg) +{ + if (msg_col > 0) + msg_putchar('\n'); + msg_outtrans_attr((char_u *)msg, HL_ATTR(HLF_CM)); + msg_putchar('\n'); +} +#endif + + void +listdigraphs(int use_headers) +{ + int i; + digr_T *dp; + result_T previous = 0; + + msg_putchar('\n'); + + dp = digraphdefault; + while (dp->char1 != NUL && !got_int) + { +#if defined(USE_UNICODE_DIGRAPHS) + digr_T tmp; + + // May need to convert the result to 'encoding'. + tmp.char1 = dp->char1; + tmp.char2 = dp->char2; + tmp.result = getexactdigraph(tmp.char1, tmp.char2, FALSE); + if (tmp.result != 0 && tmp.result != tmp.char2 + && (has_mbyte || tmp.result <= 255)) + printdigraph(&tmp, use_headers ? &previous : NULL); +#else + + if (getexactdigraph(dp->char1, dp->char2, FALSE) == dp->result + && (has_mbyte || dp->result <= 255)) + printdigraph(dp, use_headers ? &previous : NULL); +#endif + ++dp; + ui_breakcheck(); + } + + dp = (digr_T *)user_digraphs.ga_data; + for (i = 0; i < user_digraphs.ga_len && !got_int; ++i) + { +#if defined(USE_UNICODE_DIGRAPHS) + if (previous >= 0 && use_headers) + digraph_header(_("Custom")); + previous = -1; +#endif + printdigraph(dp, NULL); + ui_breakcheck(); + ++dp; + } + + // clear screen, because some digraphs may be wrong, in which case we + // messed up ScreenLines + set_must_redraw(UPD_CLEAR); +} + + static void +digraph_getlist_appendpair(digr_T *dp, list_T *l) +{ + char_u buf[30]; + char_u *p; + list_T *l2; + listitem_T *li, *li2; + + + li = listitem_alloc(); + if (li == NULL) + return; + list_append(l, li); + li->li_tv.v_type = VAR_LIST; + li->li_tv.v_lock = 0; + + l2 = list_alloc(); + li->li_tv.vval.v_list = l2; + if (l2 == NULL) + return; + ++l2->lv_refcount; + + li2 = listitem_alloc(); + if (li2 == NULL) + return; + list_append(l2, li2); + li2->li_tv.v_type = VAR_STRING; + li2->li_tv.v_lock = 0; + + buf[0] = dp->char1; + buf[1] = dp->char2; + buf[2] = NUL; + li2->li_tv.vval.v_string = vim_strsave(&buf[0]); + + li2 = listitem_alloc(); + if (li2 == NULL) + return; + list_append(l2, li2); + li2->li_tv.v_type = VAR_STRING; + li2->li_tv.v_lock = 0; + + p = buf; + if (has_mbyte) + p += (*mb_char2bytes)(dp->result, p); + else + *p++ = (char_u)dp->result; + *p = NUL; + + li2->li_tv.vval.v_string = vim_strsave(buf); +} + + static void +digraph_getlist_common(int list_all, typval_T *rettv) +{ + int i; + digr_T *dp; + + if (rettv_list_alloc(rettv) == FAIL) + return; + + if (list_all) + { + dp = digraphdefault; + while (dp->char1 != NUL && !got_int) + { +#ifdef USE_UNICODE_DIGRAPHS + digr_T tmp; + + tmp.char1 = dp->char1; + tmp.char2 = dp->char2; + tmp.result = getexactdigraph(tmp.char1, tmp.char2, FALSE); + if (tmp.result != 0 && tmp.result != tmp.char2 + && (has_mbyte || tmp.result <= 255)) + digraph_getlist_appendpair(&tmp, rettv->vval.v_list); +#else + if (getexactdigraph(dp->char1, dp->char2, FALSE) == dp->result + && (has_mbyte || dp->result <= 255)) + digraph_getlist_appendpair(dp, rettv->vval.v_list); +#endif + ++dp; + } + } + + dp = (digr_T *)user_digraphs.ga_data; + for (i = 0; i < user_digraphs.ga_len && !got_int; ++i) + { + digraph_getlist_appendpair(dp, rettv->vval.v_list); + ++dp; + } +} + +static struct dg_header_entry { + int dg_start; + char *dg_header; +} header_table[] = { + {DG_START_LATIN, N_("Latin supplement")}, + {DG_START_GREEK, N_("Greek and Coptic")}, + {DG_START_CYRILLIC, N_("Cyrillic")}, + {DG_START_HEBREW, N_("Hebrew")}, + {DG_START_ARABIC, N_("Arabic")}, + {DG_START_LATIN_EXTENDED, N_("Latin extended")}, + {DG_START_GREEK_EXTENDED, N_("Greek extended")}, + {DG_START_PUNCTUATION, N_("Punctuation")}, + {DG_START_SUB_SUPER, N_("Super- and subscripts")}, + {DG_START_CURRENCY, N_("Currency")}, + {DG_START_OTHER1, N_("Other")}, + {DG_START_ROMAN, N_("Roman numbers")}, + {DG_START_ARROWS, N_("Arrows")}, + {DG_START_MATH, N_("Mathematical operators")}, + {DG_START_TECHNICAL, N_("Technical")}, + {DG_START_OTHER2, N_("Other")}, + {DG_START_DRAWING, N_("Box drawing")}, + {DG_START_BLOCK, N_("Block elements")}, + {DG_START_SHAPES, N_("Geometric shapes")}, + {DG_START_SYMBOLS, N_("Symbols")}, + {DG_START_DINGBATS, N_("Dingbats")}, + {DG_START_CJK_SYMBOLS, N_("CJK symbols and punctuation")}, + {DG_START_HIRAGANA, N_("Hiragana")}, + {DG_START_KATAKANA, N_("Katakana")}, + {DG_START_BOPOMOFO, N_("Bopomofo")}, + {DG_START_OTHER3, N_("Other")}, + {0xfffffff, NULL}, +}; + + static void +printdigraph(digr_T *dp, result_T *previous) +{ + char_u buf[30]; + char_u *p; + + int list_width; + + if ((dy_flags & DY_UHEX) || has_mbyte) + list_width = 13; + else + list_width = 11; + + if (dp->result == 0) + return; + +#if defined(USE_UNICODE_DIGRAPHS) + if (previous != NULL) + { + int i; + + for (i = 0; header_table[i].dg_header != NULL; ++i) + if (*previous < header_table[i].dg_start + && dp->result >= header_table[i].dg_start + && dp->result < header_table[i + 1].dg_start) + { + digraph_header(_(header_table[i].dg_header)); + break; + } + *previous = dp->result; + } +#endif + if (msg_col > Columns - list_width) + msg_putchar('\n'); + if (msg_col) + while (msg_col % list_width != 0) + msg_putchar(' '); + + p = buf; + *p++ = dp->char1; + *p++ = dp->char2; + *p++ = ' '; + *p = NUL; + msg_outtrans(buf); + p = buf; + if (has_mbyte) + { + // add a space to draw a composing char on + if (enc_utf8 && utf_iscomposing(dp->result)) + *p++ = ' '; + p += (*mb_char2bytes)(dp->result, p); + } + else + *p++ = (char_u)dp->result; + *p = NUL; + msg_outtrans_attr(buf, HL_ATTR(HLF_8)); + p = buf; + if (char2cells(dp->result) == 1) + *p++ = ' '; + vim_snprintf((char *)p, sizeof(buf) - (p - buf), " %3d", dp->result); + msg_outtrans(buf); +} + +# ifdef FEAT_EVAL +/* + * Get the two digraph characters from a typval. + * Return OK or FAIL. + */ + static int +get_digraph_chars(typval_T *arg, int *char1, int *char2) +{ + char_u buf_chars[NUMBUFLEN]; + char_u *chars = tv_get_string_buf_chk(arg, buf_chars); + char_u *p = chars; + + if (p != NULL) + { + if (*p != NUL) + { + *char1 = mb_cptr2char_adv(&p); + if (*p != NUL) + { + *char2 = mb_cptr2char_adv(&p); + if (*p == NUL) + { + if (check_digraph_chars_valid(*char1, *char2)) + return OK; + return FAIL; + } + } + } + } + semsg(_(e_digraph_must_be_just_two_characters_str), chars); + return FAIL; +} + + static int +digraph_set_common(typval_T *argchars, typval_T *argdigraph) +{ + int char1, char2; + char_u *digraph; + char_u *p; + char_u buf_digraph[NUMBUFLEN]; + varnumber_T n; + + if (get_digraph_chars(argchars, &char1, &char2) == FAIL) + return FALSE; + + digraph = tv_get_string_buf_chk(argdigraph, buf_digraph); + if (digraph == NULL) + return FALSE; + p = digraph; + n = mb_cptr2char_adv(&p); + if (*p != NUL) + { + semsg(_(e_digraph_argument_must_be_one_character_str), digraph); + return FALSE; + } + + registerdigraph(char1, char2, (int)n); + return TRUE; +} +# endif + +#endif // FEAT_DIGRAPHS + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * "digraph_get()" function + */ + void +f_digraph_get(typval_T *argvars, typval_T *rettv) +{ +# ifdef FEAT_DIGRAPHS + int code; + char_u buf[NUMBUFLEN]; + char_u *digraphs; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; // Return empty string for failure + + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + + digraphs = tv_get_string_chk(&argvars[0]); + + if (digraphs == NULL) + return; + else if (STRLEN(digraphs) != 2) + { + semsg(_(e_digraph_must_be_just_two_characters_str), digraphs); + return; + } + code = digraph_get(digraphs[0], digraphs[1], FALSE); + + if (has_mbyte) + buf[(*mb_char2bytes)(code, buf)] = NUL; + else + { + buf[0] = code; + buf[1] = NUL; + } + + rettv->vval.v_string = vim_strsave(buf); +# else + emsg(_(e_no_digraphs_version)); +# endif +} + +/* + * "digraph_getlist()" function + */ + void +f_digraph_getlist(typval_T *argvars, typval_T *rettv) +{ +# ifdef FEAT_DIGRAPHS + int flag_list_all; + + if (in_vim9script() && check_for_opt_bool_arg(argvars, 0) == FAIL) + return; + + if (argvars[0].v_type == VAR_UNKNOWN) + flag_list_all = FALSE; + else + { + int error = FALSE; + varnumber_T flag = tv_get_number_chk(&argvars[0], &error); + + if (error) + return; + flag_list_all = flag ? TRUE : FALSE; + } + + digraph_getlist_common(flag_list_all, rettv); +# else + emsg(_(e_no_digraphs_version)); +# endif +} + +/* + * "digraph_set()" function + */ + void +f_digraph_set(typval_T *argvars, typval_T *rettv) +{ +# ifdef FEAT_DIGRAPHS + rettv->v_type = VAR_BOOL; + rettv->vval.v_number = VVAL_FALSE; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + if (!digraph_set_common(&argvars[0], &argvars[1])) + return; + + rettv->vval.v_number = VVAL_TRUE; +# else + emsg(_(e_no_digraphs_version)); +# endif +} + +/* + * "digraph_setlist()" function + */ + void +f_digraph_setlist(typval_T * argvars, typval_T *rettv) +{ +# ifdef FEAT_DIGRAPHS + list_T *pl, *l; + listitem_T *pli; + + rettv->v_type = VAR_BOOL; + rettv->vval.v_number = VVAL_FALSE; + + if (argvars[0].v_type != VAR_LIST) + { + emsg(_(e_digraph_setlist_argument_must_be_list_of_lists_with_two_items)); + return; + } + + pl = argvars[0].vval.v_list; + if (pl == NULL) + { + // Empty list always results in success. + rettv->vval.v_number = VVAL_TRUE; + return; + } + + FOR_ALL_LIST_ITEMS(pl, pli) + { + if (pli->li_tv.v_type != VAR_LIST) + { + emsg(_(e_digraph_setlist_argument_must_be_list_of_lists_with_two_items)); + return; + } + + l = pli->li_tv.vval.v_list; + if (l == NULL || l->lv_len != 2) + { + emsg(_(e_digraph_setlist_argument_must_be_list_of_lists_with_two_items)); + return; + } + + if (!digraph_set_common(&l->lv_first->li_tv, + &l->lv_first->li_next->li_tv)) + return; + } + rettv->vval.v_number = VVAL_TRUE; +# else + emsg(_(e_no_digraphs_version)); +# endif +} + +#endif // FEAT_EVAL + + +#if defined(FEAT_KEYMAP) || defined(PROTO) + +// structure used for b_kmap_ga.ga_data +typedef struct +{ + char_u *from; + char_u *to; +} kmap_T; + +#define KMAP_MAXLEN 20 // maximum length of "from" or "to" + +static void keymap_unload(void); + +/* + * Set up key mapping tables for the 'keymap' option. + * Returns NULL if OK, an error message for failure. This only needs to be + * used when setting the option, not later when the value has already been + * checked. + */ + char * +keymap_init(void) +{ + curbuf->b_kmap_state &= ~KEYMAP_INIT; + + if (*curbuf->b_p_keymap == NUL) + { + // Stop any active keymap and clear the table. Also remove + // b:keymap_name, as no keymap is active now. + keymap_unload(); + do_cmdline_cmd((char_u *)"unlet! b:keymap_name"); + } + else + { + char_u *buf; + size_t buflen; + + // Source the keymap file. It will contain a ":loadkeymap" command + // which will call ex_loadkeymap() below. + buflen = STRLEN(curbuf->b_p_keymap) + STRLEN(p_enc) + 14; + buf = alloc(buflen); + if (buf == NULL) + return e_out_of_memory; + + // try finding "keymap/'keymap'_'encoding'.vim" in 'runtimepath' + vim_snprintf((char *)buf, buflen, "keymap/%s_%s.vim", + curbuf->b_p_keymap, p_enc); + if (source_runtime(buf, 0) == FAIL) + { + // try finding "keymap/'keymap'.vim" in 'runtimepath' + vim_snprintf((char *)buf, buflen, "keymap/%s.vim", + curbuf->b_p_keymap); + if (source_runtime(buf, 0) == FAIL) + { + vim_free(buf); + return N_(e_keymap_file_not_found); + } + } + vim_free(buf); + } + + return NULL; +} + +/* + * ":loadkeymap" command: load the following lines as the keymap. + */ + void +ex_loadkeymap(exarg_T *eap) +{ + char_u *line; + char_u *p; + char_u *s; + kmap_T *kp; +#define KMAP_LLEN 200 // max length of "to" and "from" together + char_u buf[KMAP_LLEN + 11]; + int i; + char_u *save_cpo = p_cpo; + + if (!sourcing_a_script(eap)) + { + emsg(_(e_using_loadkeymap_not_in_sourced_file)); + return; + } + + /* + * Stop any active keymap and clear the table. + */ + keymap_unload(); + + curbuf->b_kmap_state = 0; + ga_init2(&curbuf->b_kmap_ga, sizeof(kmap_T), 20); + + // Set 'cpoptions' to "C" to avoid line continuation. + p_cpo = (char_u *)"C"; + + /* + * Get each line of the sourced file, break at the end. + */ + for (;;) + { + line = eap->getline(0, eap->cookie, 0, TRUE); + if (line == NULL) + break; + + p = skipwhite(line); + if (*p != '"' && *p != NUL && ga_grow(&curbuf->b_kmap_ga, 1) == OK) + { + kp = (kmap_T *)curbuf->b_kmap_ga.ga_data + curbuf->b_kmap_ga.ga_len; + s = skiptowhite(p); + kp->from = vim_strnsave(p, s - p); + p = skipwhite(s); + s = skiptowhite(p); + kp->to = vim_strnsave(p, s - p); + + if (kp->from == NULL || kp->to == NULL + || STRLEN(kp->from) + STRLEN(kp->to) >= KMAP_LLEN + || *kp->from == NUL || *kp->to == NUL) + { + if (kp->to != NULL && *kp->to == NUL) + emsg(_(e_empty_keymap_entry)); + vim_free(kp->from); + vim_free(kp->to); + } + else + ++curbuf->b_kmap_ga.ga_len; + } + vim_free(line); + } + + /* + * setup ":lnoremap" to map the keys + */ + for (i = 0; i < curbuf->b_kmap_ga.ga_len; ++i) + { + vim_snprintf((char *)buf, sizeof(buf), " %s %s", + ((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].from, + ((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].to); + (void)do_map(MAPTYPE_NOREMAP, buf, MODE_LANGMAP, FALSE); + } + + p_cpo = save_cpo; + + curbuf->b_kmap_state |= KEYMAP_LOADED; + status_redraw_curbuf(); +} + +/* + * Stop using 'keymap'. + */ + static void +keymap_unload(void) +{ + char_u buf[KMAP_MAXLEN + 10]; + int i; + char_u *save_cpo = p_cpo; + kmap_T *kp; + + if (!(curbuf->b_kmap_state & KEYMAP_LOADED)) + return; + + // Set 'cpoptions' to "C" to avoid line continuation. + p_cpo = (char_u *)"C"; + + // clear the ":lmap"s + kp = (kmap_T *)curbuf->b_kmap_ga.ga_data; + for (i = 0; i < curbuf->b_kmap_ga.ga_len; ++i) + { + vim_snprintf((char *)buf, sizeof(buf), " %s", kp[i].from); + (void)do_map(MAPTYPE_UNMAP, buf, MODE_LANGMAP, FALSE); + } + keymap_clear(&curbuf->b_kmap_ga); + + p_cpo = save_cpo; + + ga_clear(&curbuf->b_kmap_ga); + curbuf->b_kmap_state &= ~KEYMAP_LOADED; + status_redraw_curbuf(); +} + + void +keymap_clear(garray_T *kmap) +{ + int i; + kmap_T *kp = (kmap_T *)kmap->ga_data; + + for (i = 0; i < kmap->ga_len; ++i) + { + vim_free(kp[i].from); + vim_free(kp[i].to); + } +} +#endif // FEAT_KEYMAP diff --git a/src/dlldata.c b/src/dlldata.c new file mode 100644 index 0000000..d03124c --- /dev/null +++ b/src/dlldata.c @@ -0,0 +1,38 @@ +/********************************************************* + DllData file -- generated by MIDL compiler + + DO NOT ALTER THIS FILE + + This file is regenerated by MIDL on every IDL file compile. + + To completely reconstruct this file, delete it and rerun MIDL + on all the IDL files in this DLL, specifying this file for the + /dlldata command line option + +*********************************************************/ + +#define PROXY_DELEGATION + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +EXTERN_PROXY_FILE( if_ole ) + + +PROXYFILE_LIST_START +/* Start of list */ + REFERENCE_PROXY_FILE( if_ole ), +/* End of list */ +PROXYFILE_LIST_END + + +DLLDATA_ROUTINES( aProxyFileList, GET_DLL_CLSID ) + +#ifdef __cplusplus +} /*extern "C" */ +#endif + +/* end of generated dlldata file */ diff --git a/src/dosinst.c b/src/dosinst.c new file mode 100644 index 0000000..4eae5aa --- /dev/null +++ b/src/dosinst.c @@ -0,0 +1,2811 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * dosinst.c: Install program for Vim on MS-DOS and MS-Windows + * + * Compile with Make_mvc.mak, Make_cyg.mak or Make_ming.mak. + */ + +/* + * Include common code for dosinst.c and uninstall.c. + */ +#define DOSINST +#include "dosinst.h" +#include + +#define GVIMEXT64_PATH "GvimExt64\\gvimext.dll" +#define GVIMEXT32_PATH "GvimExt32\\gvimext.dll" + +// Macro to do an error check I was typing over and over +#define CHECK_REG_ERROR(code) \ + do { \ + if (code != ERROR_SUCCESS) \ + { \ + printf("%ld error number: %ld\n", (long)__LINE__, (long)code); \ + return 1; \ + } \ + } while (0) + +int has_vim = 0; // installable vim.exe exists +int has_gvim = 0; // installable gvim.exe exists + +char oldvimrc[BUFSIZE]; // name of existing vimrc file +char vimrc[BUFSIZE]; // name of vimrc file to create + +char *default_bat_dir = NULL; // when not NULL, use this as the default + // directory to write .bat files in +char *default_vim_dir = NULL; // when not NULL, use this as the default + // install dir for NSIS + +/* + * Structure used for each choice the user can make. + */ +struct choice +{ + int active; // non-zero when choice is active + char *text; // text displayed for this choice + void (*changefunc)(int idx); // function to change this choice + int arg; // argument for function + void (*installfunc)(int idx); // function to install this choice +}; + +struct choice choices[30]; // choices the user can make +int choice_count = 0; // number of choices available + +#define TABLE_SIZE(s) (int)ARRAYSIZE(s) + +enum +{ + compat_vi = 1, + compat_vim, + compat_some_enhancements, + compat_all_enhancements +}; +char *(compat_choices[]) = +{ + "\nChoose the default way to run Vim:", + "Vi compatible", + "Vim default", + "with some Vim enhancements", + "with syntax highlighting and other features switched on", +}; +int compat_choice = (int)compat_all_enhancements; +char *compat_text = "- run Vim %s"; + +enum +{ + remap_no = 1, + remap_win +}; +char *(remap_choices[]) = +{ + "\nChoose:", + "Do not remap keys for Windows behavior", + "Remap a few keys for Windows behavior (CTRL-V, CTRL-C, CTRL-F, etc)", +}; +int remap_choice = (int)remap_no; +char *remap_text = "- %s"; + +enum +{ + mouse_xterm = 1, + mouse_mswin, + mouse_default +}; +char *(mouse_choices[]) = +{ + "\nChoose the way how Vim uses the mouse:", + "right button extends selection (the Unix way)", + "right button has a popup menu, left button starts select mode (the Windows way)", + "right button has a popup menu, left button starts visual mode", +}; +int mouse_choice = (int)mouse_default; +char *mouse_text = "- The mouse %s"; + +enum +{ + vimfiles_dir_none = 1, + vimfiles_dir_vim, + vimfiles_dir_home +}; +static char *(vimfiles_dir_choices[]) = +{ + "\nCreate plugin directories:", + "No", + "In the VIM directory", + "In your HOME directory", +}; + +// non-zero when selected to install the popup menu entry. +static int install_popup = 0; + +// non-zero when selected to install the "Open with" entry. +static int install_openwith = 0; + +// non-zero when need to add an uninstall entry in the registry +static int need_uninstall_entry = 0; + +/* + * Definitions of the directory name (under $VIM) of the vimfiles directory + * and its subdirectories: + */ +static char *(vimfiles_subdirs[]) = +{ + "colors", + "compiler", + "doc", + "ftdetect", + "ftplugin", + "indent", + "keymap", + "plugin", + "syntax", +}; + +/* + * Obtain a choice from a table. + * First entry is a question, others are choices. + */ + static int +get_choice(char **table, int entries) +{ + int answer; + int idx; + char dummy[100]; + + do + { + for (idx = 0; idx < entries; ++idx) + { + if (idx) + printf("%2d ", idx); + puts(table[idx]); + } + printf("Choice: "); + if (scanf("%d", &answer) != 1) + { + scanf("%99s", dummy); + answer = 0; + } + } + while (answer < 1 || answer >= entries); + + return answer; +} + +/* + * Check if the user unpacked the archives properly. + * Sets "runtimeidx". + */ + static void +check_unpack(void) +{ + char buf[BUFSIZE]; + FILE *fd; + struct stat st; + + // check for presence of the correct version number in installdir[] + runtimeidx = strlen(installdir) - strlen(VIM_VERSION_NODOT); + if (runtimeidx <= 0 + || stricmp(installdir + runtimeidx, VIM_VERSION_NODOT) != 0 + || (installdir[runtimeidx - 1] != '/' + && installdir[runtimeidx - 1] != '\\')) + { + printf("ERROR: Install program not in directory \"%s\"\n", + VIM_VERSION_NODOT); + printf("This program can only work when it is located in its original directory\n"); + myexit(1); + } + + // check if filetype.vim is present, which means the runtime archive has + // been unpacked + sprintf(buf, "%s\\filetype.vim", installdir); + if (stat(buf, &st) < 0) + { + printf("ERROR: Cannot find filetype.vim in \"%s\"\n", installdir); + printf("It looks like you did not unpack the runtime archive.\n"); + printf("You must unpack the runtime archive \"%srt.zip\" before installing.\n", + VIM_VERSION_NODOT); + myexit(1); + } + + // Check if vim.exe or gvim.exe is in the current directory. + if ((fd = fopen("gvim.exe", "r")) != NULL) + { + fclose(fd); + has_gvim = 1; + } + if ((fd = fopen("vim.exe", "r")) != NULL) + { + fclose(fd); + has_vim = 1; + } + if (!has_gvim && !has_vim) + { + printf("ERROR: Cannot find any Vim executables in \"%s\"\n\n", + installdir); + myexit(1); + } +} + +/* + * Compare paths "p[plen]" to "q[qlen]". Return 0 if they match. + * Ignores case and differences between '/' and '\'. + * "plen" and "qlen" can be negative, strlen() is used then. + */ + static int +pathcmp(char *p, int plen, char *q, int qlen) +{ + int i; + + if (plen < 0) + plen = strlen(p); + if (qlen < 0) + qlen = strlen(q); + for (i = 0; ; ++i) + { + // End of "p": check if "q" also ends or just has a slash. + if (i == plen) + { + if (i == qlen) // match + return 0; + if (i == qlen - 1 && (q[i] == '\\' || q[i] == '/')) + return 0; // match with trailing slash + return 1; // no match + } + + // End of "q": check if "p" also ends or just has a slash. + if (i == qlen) + { + if (i == plen) // match + return 0; + if (i == plen - 1 && (p[i] == '\\' || p[i] == '/')) + return 0; // match with trailing slash + return 1; // no match + } + + if (!(mytoupper(p[i]) == mytoupper(q[i]) + || ((p[i] == '/' || p[i] == '\\') + && (q[i] == '/' || q[i] == '\\')))) + return 1; // no match + } + //NOTREACHED +} + +/* + * If the executable "**destination" is in the install directory, find another + * one in $PATH. + * On input "**destination" is the path of an executable in allocated memory + * (or NULL). + * "*destination" is set to NULL or the location of the file. + */ + static void +findoldfile(char **destination) +{ + char *bp = *destination; + size_t indir_l = strlen(installdir); + char *cp; + char *tmpname; + char *farname; + + /* + * No action needed if exe not found or not in this directory. + */ + if (bp == NULL || strnicmp(bp, installdir, indir_l) != 0) + return; + cp = bp + indir_l; + if (strchr("/\\", *cp++) == NULL + || strchr(cp, '\\') != NULL + || strchr(cp, '/') != NULL) + return; + + tmpname = alloc(strlen(cp) + 1); + strcpy(tmpname, cp); + tmpname[strlen(tmpname) - 1] = 'x'; // .exe -> .exx + + if (access(tmpname, 0) == 0) + { + printf("\nERROR: %s and %s clash. Remove or rename %s.\n", + tmpname, cp, tmpname); + myexit(1); + } + + if (rename(cp, tmpname) != 0) + { + printf("\nERROR: failed to rename %s to %s: %s\n", + cp, tmpname, strerror(0)); + myexit(1); + } + + farname = searchpath_save(cp); + + if (rename(tmpname, cp) != 0) + { + printf("\nERROR: failed to rename %s back to %s: %s\n", + tmpname, cp, strerror(0)); + myexit(1); + } + + free(*destination); + free(tmpname); + *destination = farname; +} + +/* + * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path. + * When "check_bat_only" is TRUE, only find "default_bat_dir". + */ + static void +find_bat_exe(int check_bat_only) +{ + int i; + + // avoid looking in the "installdir" by chdir to system root + mch_chdir(sysdrive); + mch_chdir("\\"); + + for (i = 1; i < TARGET_COUNT; ++i) + { + targets[i].oldbat = searchpath_save(targets[i].batname); + if (!check_bat_only) + targets[i].oldexe = searchpath_save(targets[i].exename); + + if (default_bat_dir == NULL && targets[i].oldbat != NULL) + { + default_bat_dir = alloc(strlen(targets[i].oldbat) + 1); + strcpy(default_bat_dir, targets[i].oldbat); + remove_tail(default_bat_dir); + } + if (check_bat_only && targets[i].oldbat != NULL) + { + free(targets[i].oldbat); + targets[i].oldbat = NULL; + } + } + + mch_chdir(installdir); +} + +/* + * Get the value of $VIMRUNTIME or $VIM and write it in $TEMP/vimini.ini, so + * that NSIS can read it. + * When not set, use the directory of a previously installed Vim. + */ + static void +get_vim_env(void) +{ + char *vim; + char buf[BUFSIZE]; + FILE *fd; + char fname[BUFSIZE]; + + // First get $VIMRUNTIME. If it's set, remove the tail. + vim = getenv("VIMRUNTIME"); + if (vim != NULL && *vim != 0 && strlen(vim) < sizeof(buf)) + { + strcpy(buf, vim); + remove_tail(buf); + vim = buf; + } + else + { + vim = getenv("VIM"); + if (vim == NULL || *vim == 0) + { + // Use the directory from an old uninstall entry. + if (default_vim_dir != NULL) + vim = default_vim_dir; + else + // Let NSIS know there is no default, it should use + // $PROGRAMFILES. + vim = ""; + } + } + + // NSIS also uses GetTempPath(), thus we should get the same directory + // name as where NSIS will look for vimini.ini. + GetTempPath(sizeof(fname) - 12, fname); + add_pathsep(fname); + strcat(fname, "vimini.ini"); + + fd = fopen(fname, "w"); + if (fd != NULL) + { + // Make it look like an .ini file, so that NSIS can read it with a + // ReadINIStr command. + fprintf(fd, "[vimini]\n"); + fprintf(fd, "dir=\"%s\"\n", vim); + fclose(fd); + } + else + { + printf("Failed to open %s\n", fname); + sleep(2); + } +} + +static int num_windows; + +/* + * Callback used for EnumWindows(): + * Count the window if the title looks like it is for the uninstaller. + */ +//ARGSUSED + static BOOL CALLBACK +window_cb(HWND hwnd, LPARAM lparam UNUSED) +{ + char title[256]; + + title[0] = 0; + GetWindowText(hwnd, title, 256); + if (strstr(title, "Vim ") != NULL && strstr(title, " Uninstall") != NULL) + ++num_windows; + return TRUE; +} + +/* + * Run the uninstaller silently. + */ + static int +run_silent_uninstall(char *uninst_exe) +{ + char vimrt_dir[BUFSIZE]; + char temp_uninst[BUFSIZE]; + char temp_dir[MAX_PATH]; + char buf[BUFSIZE * 2 + 10]; + int i; + DWORD tick; + + strcpy(vimrt_dir, uninst_exe); + remove_tail(vimrt_dir); + + if (!GetTempPath(sizeof(temp_dir), temp_dir)) + return FAIL; + + // Copy the uninstaller to a temporary exe. + tick = GetTickCount(); + for (i = 0; ; i++) + { + sprintf(temp_uninst, "%s\\vimun%04X.exe", temp_dir, + (unsigned int)((i + tick) & 0xFFFF)); + if (CopyFile(uninst_exe, temp_uninst, TRUE)) + break; + if (GetLastError() != ERROR_FILE_EXISTS) + return FAIL; + if (i == 65535) + return FAIL; + } + + // Run the copied uninstaller silently. + if (strchr(temp_uninst, ' ') != NULL) + sprintf(buf, "\"%s\" /S _?=%s", temp_uninst, vimrt_dir); + else + sprintf(buf, "%s /S _?=%s", temp_uninst, vimrt_dir); + run_command(buf); + + DeleteFile(temp_uninst); + return OK; +} + +/* + * Check for already installed Vims. + * Return non-zero when found one. + */ + static int +uninstall_check(int skip_question) +{ + HKEY key_handle; + HKEY uninstall_key_handle; + char *uninstall_key = "software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; + char subkey_name_buff[BUFSIZE]; + char temp_string_buffer[BUFSIZE-2]; + DWORD local_bufsize; + FILETIME temp_pfiletime; + DWORD key_index; + char input; + long code; + DWORD value_type; + DWORD orig_num_keys; + DWORD new_num_keys; + DWORD allow_silent; + int foundone = 0; + + code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0, + KEY_WOW64_64KEY | KEY_READ, &key_handle); + CHECK_REG_ERROR(code); + + key_index = 0; + while (TRUE) + { + local_bufsize = sizeof(subkey_name_buff); + if (RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize, + NULL, NULL, NULL, &temp_pfiletime) == ERROR_NO_MORE_ITEMS) + break; + + if (strncmp("Vim", subkey_name_buff, 3) == 0) + { + // Open the key named Vim* + code = RegOpenKeyEx(key_handle, subkey_name_buff, 0, + KEY_WOW64_64KEY | KEY_READ, &uninstall_key_handle); + CHECK_REG_ERROR(code); + + // get the DisplayName out of it to show the user + local_bufsize = sizeof(temp_string_buffer); + code = RegQueryValueEx(uninstall_key_handle, "displayname", 0, + &value_type, (LPBYTE)temp_string_buffer, + &local_bufsize); + CHECK_REG_ERROR(code); + + allow_silent = 0; + if (skip_question) + { + DWORD varsize = sizeof(DWORD); + + RegQueryValueEx(uninstall_key_handle, "AllowSilent", 0, + &value_type, (LPBYTE)&allow_silent, + &varsize); + } + + foundone = 1; + printf("\n*********************************************************\n"); + printf("Vim Install found what looks like an existing Vim version.\n"); + printf("The name of the entry is:\n"); + printf("\n \"%s\"\n\n", temp_string_buffer); + + printf("Installing the new version will disable part of the existing version.\n"); + printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n"); + printf("the popup menu will use the new version)\n"); + + if (skip_question) + printf("\nRunning uninstall program for \"%s\"\n", temp_string_buffer); + else + printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer); + fflush(stdout); + + // get the UninstallString + local_bufsize = sizeof(temp_string_buffer); + code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0, + &value_type, (LPBYTE)temp_string_buffer, &local_bufsize); + CHECK_REG_ERROR(code); + + // Remember the directory, it is used as the default for NSIS. + default_vim_dir = alloc(strlen(temp_string_buffer) + 1); + strcpy(default_vim_dir, temp_string_buffer); + remove_tail(default_vim_dir); + remove_tail(default_vim_dir); + + input = 'n'; + do + { + if (input != 'n') + printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input); + + if (skip_question) + input = 'y'; + else + { + rewind(stdin); + scanf("%c", &input); + } + switch (input) + { + case 'y': + case 'Y': + // save the number of uninstall keys so we can know if + // it changed + RegQueryInfoKey(key_handle, NULL, NULL, NULL, + &orig_num_keys, NULL, NULL, NULL, + NULL, NULL, NULL, NULL); + + // Find existing .bat files before deleting them. + find_bat_exe(TRUE); + + if (allow_silent) + { + if (run_silent_uninstall(temp_string_buffer) + == FAIL) + allow_silent = 0; // Retry with non silent. + } + if (!allow_silent) + { + // Execute the uninstall program. Put it in double + // quotes if there is an embedded space. + { + char buf[BUFSIZE]; + + if (strchr(temp_string_buffer, ' ') != NULL) + sprintf(buf, "\"%s\"", temp_string_buffer); + else + strcpy(buf, temp_string_buffer); + run_command(buf); + } + + // Count the number of windows with a title that + // match the installer, so that we can check when + // it's done. The uninstaller copies itself, + // executes the copy and exits, thus we can't wait + // for the process to finish. + sleep(1); // wait for uninstaller to start up + num_windows = 0; + EnumWindows(window_cb, 0); + if (num_windows == 0) + { + // Did not find the uninstaller, ask user to + // press Enter when done. Just in case. + printf("Press Enter when the uninstaller is finished\n"); + rewind(stdin); + (void)getchar(); + } + else + { + printf("Waiting for the uninstaller to finish (press CTRL-C to abort)."); + do + { + printf("."); + fflush(stdout); + sleep(1); // wait for the uninstaller to + // finish + num_windows = 0; + EnumWindows(window_cb, 0); + } while (num_windows > 0); + } + } + printf("\nDone!\n"); + + // Check if an uninstall reg key was deleted. + // if it was, we want to decrement key_index. + // if we don't do this, we will skip the key + // immediately after any key that we delete. + RegQueryInfoKey(key_handle, NULL, NULL, NULL, + &new_num_keys, NULL, NULL, NULL, + NULL, NULL, NULL, NULL); + if (new_num_keys < orig_num_keys) + key_index--; + + input = 'y'; + break; + + case 'n': + case 'N': + // Do not uninstall + input = 'n'; + break; + + default: // just drop through and redo the loop + break; + } + + } while (input != 'n' && input != 'y'); + + RegCloseKey(uninstall_key_handle); + } + + key_index++; + } + RegCloseKey(key_handle); + + return foundone; +} + +/* + * Find out information about the system. + */ + static void +inspect_system(void) +{ + char *p; + char buf[BUFSIZE]; + FILE *fd; + int i; + int foundone; + + // This may take a little while, let the user know what we're doing. + printf("Inspecting system...\n"); + + /* + * If $VIM is set, check that it's pointing to our directory. + */ + p = getenv("VIM"); + if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0) + { + printf("------------------------------------------------------\n"); + printf("$VIM is set to \"%s\".\n", p); + printf("This is different from where this version of Vim is:\n"); + strcpy(buf, installdir); + *(buf + runtimeidx - 1) = NUL; + printf("\"%s\"\n", buf); + printf("You must adjust or remove the setting of $VIM,\n"); + if (interactive) + { + printf("to be able to use this install program.\n"); + myexit(1); + } + printf("otherwise Vim WILL NOT WORK properly!\n"); + printf("------------------------------------------------------\n"); + } + + /* + * If $VIMRUNTIME is set, check that it's pointing to our runtime directory. + */ + p = getenv("VIMRUNTIME"); + if (p != NULL && pathcmp(p, -1, installdir, -1) != 0) + { + printf("------------------------------------------------------\n"); + printf("$VIMRUNTIME is set to \"%s\".\n", p); + printf("This is different from where this version of Vim is:\n"); + printf("\"%s\"\n", installdir); + printf("You must adjust or remove the setting of $VIMRUNTIME,\n"); + if (interactive) + { + printf("to be able to use this install program.\n"); + myexit(1); + } + printf("otherwise Vim WILL NOT WORK properly!\n"); + printf("------------------------------------------------------\n"); + } + + /* + * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path. + */ + find_bat_exe(FALSE); + + /* + * A .exe in the install directory may be found anyway on Windows 2000. + * Check for this situation and find another executable if necessary. + * w.briscoe@ponl.com 2001-01-20 + */ + foundone = 0; + for (i = 1; i < TARGET_COUNT; ++i) + { + findoldfile(&(targets[i].oldexe)); + if (targets[i].oldexe != NULL) + foundone = 1; + } + + if (foundone) + { + printf("Warning: Found Vim executable(s) in your $PATH:\n"); + for (i = 1; i < TARGET_COUNT; ++i) + if (targets[i].oldexe != NULL) + printf("%s\n", targets[i].oldexe); + printf("It will be used instead of the version you are installing.\n"); + printf("Please delete or rename it, or adjust your $PATH setting.\n"); + } + + /* + * Check if there is an existing ../_vimrc or ../.vimrc file. + */ + strcpy(oldvimrc, installdir); + strcpy(oldvimrc + runtimeidx, "_vimrc"); + if ((fd = fopen(oldvimrc, "r")) == NULL) + { + strcpy(oldvimrc + runtimeidx, "vimrc~1"); // short version of .vimrc + if ((fd = fopen(oldvimrc, "r")) == NULL) + { + strcpy(oldvimrc + runtimeidx, ".vimrc"); + fd = fopen(oldvimrc, "r"); + } + } + if (fd != NULL) + fclose(fd); + else + *oldvimrc = NUL; +} + +/* + * Add a dummy choice to avoid that the numbering changes depending on items + * in the environment. The user may type a number he remembered without + * looking. + */ + static void +add_dummy_choice(void) +{ + choices[choice_count].installfunc = NULL; + choices[choice_count].active = 0; + choices[choice_count].changefunc = NULL; + choices[choice_count].text = NULL; + choices[choice_count].arg = 0; + ++choice_count; +} + +//////////////////////////////////////////////// +// stuff for creating the batch files. + +/* + * Install the vim.bat, gvim.bat, etc. files. + */ + static void +install_bat_choice(int idx) +{ + char *batpath = targets[choices[idx].arg].batpath; + char *oldname = targets[choices[idx].arg].oldbat; + char *exename = targets[choices[idx].arg].exenamearg; + char *vimarg = targets[choices[idx].arg].exearg; + FILE *fd; + + if (*batpath == NUL) + return; + + fd = fopen(batpath, "w"); + if (fd == NULL) + { + printf("\nERROR: Cannot open \"%s\" for writing.\n", batpath); + return; + } + + need_uninstall_entry = 1; + + fprintf(fd, "@echo off\n"); + fprintf(fd, "rem -- Run Vim --\n"); + fprintf(fd, VIMBAT_UNINSTKEY "\n"); + fprintf(fd, "\n"); + fprintf(fd, "setlocal\n"); + + /* + * Don't use double quotes for the "set" argument, also when it + * contains a space. The quotes would be included in the value. + * The order of preference is: + * 1. $VIMRUNTIME/vim.exe (user preference) + * 2. $VIM/vim81/vim.exe (hard coded version) + * 3. installdir/vim.exe (hard coded install directory) + */ + fprintf(fd, "set VIM_EXE_DIR=%s\n", installdir); + fprintf(fd, "if exist \"%%VIM%%\\%s\\%s\" set VIM_EXE_DIR=%%VIM%%\\%s\n", + VIM_VERSION_NODOT, exename, VIM_VERSION_NODOT); + fprintf(fd, "if exist \"%%VIMRUNTIME%%\\%s\" set VIM_EXE_DIR=%%VIMRUNTIME%%\n", exename); + fprintf(fd, "\n"); + + // Give an error message when the executable could not be found. + fprintf(fd, "if not exist \"%%VIM_EXE_DIR%%\\%s\" (\n", exename); + fprintf(fd, " echo \"%%VIM_EXE_DIR%%\\%s\" not found\n", exename); + fprintf(fd, " goto :eof\n"); + fprintf(fd, ")\n"); + fprintf(fd, "\n"); + + if (*exename == 'g') + { + fprintf(fd, "rem check --nofork argument\n"); + fprintf(fd, "set VIMNOFORK=\n"); + fprintf(fd, ":loopstart\n"); + fprintf(fd, "if .%%1==. goto loopend\n"); + fprintf(fd, "if .%%1==.--nofork (\n"); + fprintf(fd, " set VIMNOFORK=1\n"); + fprintf(fd, ") else if .%%1==.-f (\n"); + fprintf(fd, " set VIMNOFORK=1\n"); + fprintf(fd, ")\n"); + fprintf(fd, "shift\n"); + fprintf(fd, "goto loopstart\n"); + fprintf(fd, ":loopend\n"); + fprintf(fd, "\n"); + } + + if (*exename == 'g') + { + // For gvim.exe use "start /b" to avoid that the console window + // stays open. + fprintf(fd, "if .%%VIMNOFORK%%==.1 (\n"); + fprintf(fd, " start \"dummy\" /b /wait "); + // Always use quotes, $VIM or $VIMRUNTIME might have a space. + fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n", + exename, vimarg); + fprintf(fd, ") else (\n"); + fprintf(fd, " start \"dummy\" /b "); + // Always use quotes, $VIM or $VIMRUNTIME might have a space. + fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n", + exename, vimarg); + fprintf(fd, ")\n"); + } + else + { + // Always use quotes, $VIM or $VIMRUNTIME might have a space. + fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n", + exename, vimarg); + } + + fclose(fd); + printf("%s has been %s\n", batpath, + oldname == NULL ? "created" : "overwritten"); +} + +/* + * Make the text string for choice "idx". + * The format "fmt" is must have one %s item, which "arg" is used for. + */ + static void +alloc_text(int idx, char *fmt, char *arg) +{ + if (choices[idx].text != NULL) + free(choices[idx].text); + + choices[idx].text = alloc(strlen(fmt) + strlen(arg) - 1); + sprintf(choices[idx].text, fmt, arg); +} + +/* + * Toggle the "Overwrite .../vim.bat" to "Don't overwrite". + */ + static void +toggle_bat_choice(int idx) +{ + char *batname = targets[choices[idx].arg].batpath; + char *oldname = targets[choices[idx].arg].oldbat; + + if (*batname == NUL) + { + alloc_text(idx, " Overwrite %s", oldname); + strcpy(batname, oldname); + } + else + { + alloc_text(idx, " Do NOT overwrite %s", oldname); + *batname = NUL; + } +} + +/* + * Do some work for a batch file entry: Append the batch file name to the path + * and set the text for the choice. + */ + static void +set_bat_text(int idx, char *batpath, char *name) +{ + strcat(batpath, name); + + alloc_text(idx, " Create %s", batpath); +} + +/* + * Select a directory to write the batch file line. + */ + static void +change_bat_choice(int idx) +{ + char *path; + char *batpath; + char *name; + int n; + char *s; + char *p; + int count; + char **names = NULL; + int i; + int target = choices[idx].arg; + + name = targets[target].batname; + batpath = targets[target].batpath; + + path = getenv("PATH"); + if (path == NULL) + { + printf("\nERROR: The variable $PATH is not set\n"); + return; + } + + /* + * first round: count number of names in path; + * second round: save names to names[]. + */ + for (;;) + { + count = 1; + for (p = path; *p; ) + { + s = strchr(p, ';'); + if (s == NULL) + s = p + strlen(p); + if (names != NULL) + { + names[count] = alloc(s - p + 1); + strncpy(names[count], p, s - p); + names[count][s - p] = NUL; + } + ++count; + p = s; + if (*p != NUL) + ++p; + } + if (names != NULL) + break; + names = alloc((count + 1) * sizeof(char *)); + } + names[0] = alloc(50); + sprintf(names[0], "Select directory to create %s in:", name); + names[count] = alloc(50); + if (choices[idx].arg == 0) + sprintf(names[count], "Do not create any .bat file."); + else + sprintf(names[count], "Do not create a %s file.", name); + n = get_choice(names, count + 1); + + if (n == count) + { + // Selected last item, don't create bat file. + *batpath = NUL; + if (choices[idx].arg != 0) + alloc_text(idx, " Do NOT create %s", name); + } + else + { + // Selected one of the paths. For the first item only keep the path, + // for the others append the batch file name. + strcpy(batpath, names[n]); + add_pathsep(batpath); + if (choices[idx].arg != 0) + set_bat_text(idx, batpath, name); + } + + for (i = 0; i <= count; ++i) + free(names[i]); + free(names); +} + +char *bat_text_yes = "Install .bat files to use Vim at the command line:"; +char *bat_text_no = "do NOT install .bat files to use Vim at the command line"; + + static void +change_main_bat_choice(int idx) +{ + int i; + + // let the user select a default directory or NONE + change_bat_choice(idx); + + if (targets[0].batpath[0] != NUL) + choices[idx].text = bat_text_yes; + else + choices[idx].text = bat_text_no; + + // update the individual batch file selections + for (i = 1; i < TARGET_COUNT; ++i) + { + // Only make it active when the first item has a path and the vim.exe + // or gvim.exe exists (there is a changefunc then). + if (targets[0].batpath[0] != NUL + && choices[idx + i].changefunc != NULL) + { + choices[idx + i].active = 1; + if (choices[idx + i].changefunc == change_bat_choice + && targets[i].batpath[0] != NUL) + { + strcpy(targets[i].batpath, targets[0].batpath); + set_bat_text(idx + i, targets[i].batpath, targets[i].batname); + } + } + else + choices[idx + i].active = 0; + } +} + +/* + * Initialize a choice for creating a batch file. + */ + static void +init_bat_choice(int target) +{ + char *batpath = targets[target].batpath; + char *oldbat = targets[target].oldbat; + char *p; + int i; + + choices[choice_count].arg = target; + choices[choice_count].installfunc = install_bat_choice; + choices[choice_count].active = 1; + choices[choice_count].text = NULL; // will be set below + if (oldbat != NULL) + { + // A [g]vim.bat exists: Only choice is to overwrite it or not. + choices[choice_count].changefunc = toggle_bat_choice; + *batpath = NUL; + toggle_bat_choice(choice_count); + } + else + { + if (default_bat_dir != NULL) + // Prefer using the same path as an existing .bat file. + strcpy(batpath, default_bat_dir); + else + { + // No [g]vim.bat exists: Write it to a directory in $PATH. Use + // $WINDIR by default, if it's empty the first item in $PATH. + p = getenv("WINDIR"); + if (p != NULL && *p != NUL) + strcpy(batpath, p); + else + { + p = getenv("PATH"); + if (p == NULL || *p == NUL) // "cannot happen" + strcpy(batpath, "C:/Windows"); + else + { + i = 0; + while (*p != NUL && *p != ';') + batpath[i++] = *p++; + batpath[i] = NUL; + } + } + } + add_pathsep(batpath); + set_bat_text(choice_count, batpath, targets[target].batname); + + choices[choice_count].changefunc = change_bat_choice; + } + ++choice_count; +} + +/* + * Set up the choices for installing .bat files. + * For these items "arg" is the index in targets[]. + */ + static void +init_bat_choices(void) +{ + int i; + + // The first item is used to switch installing batch files on/off and + // setting the default path. + choices[choice_count].text = bat_text_yes; + choices[choice_count].changefunc = change_main_bat_choice; + choices[choice_count].installfunc = NULL; + choices[choice_count].active = 1; + choices[choice_count].arg = 0; + ++choice_count; + + // Add items for each batch file target. Only used when not disabled by + // the first item. When a .exe exists, don't offer to create a .bat. + for (i = 1; i < TARGET_COUNT; ++i) + if (targets[i].oldexe == NULL + && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim)) + init_bat_choice(i); + else + add_dummy_choice(); +} + +/* + * Install the vimrc file. + */ + static void +install_vimrc(int idx UNUSED) +{ + FILE *fd, *tfd; + char *fname; + + // If an old vimrc file exists, overwrite it. + // Otherwise create a new one. + if (*oldvimrc != NUL) + fname = oldvimrc; + else + fname = vimrc; + + fd = fopen(fname, "w"); + if (fd == NULL) + { + printf("\nERROR: Cannot open \"%s\" for writing.\n", fname); + return; + } + switch (compat_choice) + { + case compat_vi: + fprintf(fd, "\" Vi compatible\n"); + fprintf(fd, "set compatible\n"); + break; + case compat_vim: + fprintf(fd, "\" Vim's default behavior\n"); + fprintf(fd, "if &compatible\n"); + fprintf(fd, " set nocompatible\n"); + fprintf(fd, "endif\n"); + break; + case compat_some_enhancements: + fprintf(fd, "\" Vim with some enhancements\n"); + fprintf(fd, "source $VIMRUNTIME/defaults.vim\n"); + break; + case compat_all_enhancements: + fprintf(fd, "\" Vim with all enhancements\n"); + fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n"); + break; + } + switch (remap_choice) + { + case remap_no: + break; + case remap_win: + fprintf(fd, "\n"); + fprintf(fd, "\" Remap a few keys for Windows behavior\n"); + fprintf(fd, "source $VIMRUNTIME/mswin.vim\n"); + break; + } + switch (mouse_choice) + { + case mouse_xterm: + fprintf(fd, "\n"); + fprintf(fd, "\" Mouse behavior (the Unix way)\n"); + fprintf(fd, "behave xterm\n"); + break; + case mouse_mswin: + fprintf(fd, "\n"); + fprintf(fd, "\" Mouse behavior (the Windows way)\n"); + fprintf(fd, "behave mswin\n"); + break; + case mouse_default: + break; + } + if ((tfd = fopen("diff.exe", "r")) != NULL) + { + // Use the diff.exe that comes with the self-extracting gvim.exe. + fclose(tfd); + fprintf(fd, "\n"); + fprintf(fd, "\" Use the internal diff if available.\n"); + fprintf(fd, "\" Otherwise use the special 'diffexpr' for Windows.\n"); + fprintf(fd, "if &diffopt !~# 'internal'\n"); + fprintf(fd, " set diffexpr=MyDiff()\n"); + fprintf(fd, "endif\n"); + fprintf(fd, "function MyDiff()\n"); + fprintf(fd, " let opt = '-a --binary '\n"); + fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n"); + fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n"); + // Use quotes only when needed, they may cause trouble. + // Always escape "!". + fprintf(fd, " let arg1 = v:fname_in\n"); + fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n"); + fprintf(fd, " let arg1 = substitute(arg1, '!', '\\!', 'g')\n"); + fprintf(fd, " let arg2 = v:fname_new\n"); + fprintf(fd, " if arg2 =~ ' ' | let arg2 = '\"' . arg2 . '\"' | endif\n"); + fprintf(fd, " let arg2 = substitute(arg2, '!', '\\!', 'g')\n"); + fprintf(fd, " let arg3 = v:fname_out\n"); + fprintf(fd, " if arg3 =~ ' ' | let arg3 = '\"' . arg3 . '\"' | endif\n"); + fprintf(fd, " let arg3 = substitute(arg3, '!', '\\!', 'g')\n"); + + // If the path has a space: When using cmd.exe (Win NT/2000/XP) put + // quotes around the diff command and rely on the default value of + // shellxquote to solve the quoting problem for the whole command. + // + // Otherwise put a double quote just before the space and at the + // end of the command. Putting quotes around the whole thing + // doesn't work on Win 95/98/ME. This is mostly guessed! + fprintf(fd, " if $VIMRUNTIME =~ ' '\n"); + fprintf(fd, " if &sh =~ '\\ ' . arg3\n"); + fprintf(fd, " if exists('l:shxq_sav')\n"); + fprintf(fd, " let &shellxquote=l:shxq_sav\n"); + fprintf(fd, " endif\n"); + fprintf(fd, "endfunction\n"); + fprintf(fd, "\n"); + } + fclose(fd); + printf("%s has been written\n", fname); +} + + static void +change_vimrc_choice(int idx) +{ + if (choices[idx].installfunc != NULL) + { + // Switch to NOT change or create a vimrc file. + if (*oldvimrc != NUL) + alloc_text(idx, "Do NOT change startup file %s", oldvimrc); + else + alloc_text(idx, "Do NOT create startup file %s", vimrc); + choices[idx].installfunc = NULL; + choices[idx + 1].active = 0; + choices[idx + 2].active = 0; + choices[idx + 3].active = 0; + } + else + { + // Switch to change or create a vimrc file. + if (*oldvimrc != NUL) + alloc_text(idx, "Overwrite startup file %s with:", oldvimrc); + else + alloc_text(idx, "Create startup file %s with:", vimrc); + choices[idx].installfunc = install_vimrc; + choices[idx + 1].active = 1; + choices[idx + 2].active = 1; + choices[idx + 3].active = 1; + } +} + +/* + * Change the choice how to run Vim. + */ + static void +change_run_choice(int idx) +{ + compat_choice = get_choice(compat_choices, TABLE_SIZE(compat_choices)); + alloc_text(idx, compat_text, compat_choices[compat_choice]); +} + +/* + * Change the choice if keys are to be remapped. + */ + static void +change_remap_choice(int idx) +{ + remap_choice = get_choice(remap_choices, TABLE_SIZE(remap_choices)); + alloc_text(idx, remap_text, remap_choices[remap_choice]); +} + +/* + * Change the choice how to select text. + */ + static void +change_mouse_choice(int idx) +{ + mouse_choice = get_choice(mouse_choices, TABLE_SIZE(mouse_choices)); + alloc_text(idx, mouse_text, mouse_choices[mouse_choice]); +} + + static void +init_vimrc_choices(void) +{ + // set path for a new _vimrc file (also when not used) + strcpy(vimrc, installdir); + strcpy(vimrc + runtimeidx, "_vimrc"); + + // Set opposite value and then toggle it by calling change_vimrc_choice() + if (*oldvimrc == NUL) + choices[choice_count].installfunc = NULL; + else + choices[choice_count].installfunc = install_vimrc; + choices[choice_count].text = NULL; + change_vimrc_choice(choice_count); + choices[choice_count].changefunc = change_vimrc_choice; + choices[choice_count].active = 1; + ++choice_count; + + // default way to run Vim + alloc_text(choice_count, compat_text, compat_choices[compat_choice]); + choices[choice_count].changefunc = change_run_choice; + choices[choice_count].installfunc = NULL; + choices[choice_count].active = (*oldvimrc == NUL); + ++choice_count; + + // Whether to remap keys + alloc_text(choice_count, remap_text , remap_choices[remap_choice]); + choices[choice_count].changefunc = change_remap_choice; + choices[choice_count].installfunc = NULL; + choices[choice_count].active = (*oldvimrc == NUL); + ++choice_count; + + // default way to use the mouse + alloc_text(choice_count, mouse_text, mouse_choices[mouse_choice]); + choices[choice_count].changefunc = change_mouse_choice; + choices[choice_count].installfunc = NULL; + choices[choice_count].active = (*oldvimrc == NUL); + ++choice_count; +} + + static LONG +reg_create_key( + HKEY root, + const char *subkey, + PHKEY phKey, + DWORD flag) +{ + DWORD disp; + + *phKey = NULL; + return RegCreateKeyEx( + root, subkey, + 0, NULL, REG_OPTION_NON_VOLATILE, + flag | KEY_WRITE, + NULL, phKey, &disp); +} + + static LONG +reg_set_string_value( + HKEY hKey, + const char *value_name, + const char *data) +{ + return RegSetValueEx(hKey, value_name, 0, REG_SZ, + (LPBYTE)data, (DWORD)(1 + strlen(data))); +} + + static LONG +reg_create_key_and_value( + HKEY hRootKey, + const char *subkey, + const char *value_name, + const char *data, + DWORD flag) +{ + HKEY hKey; + LONG lRet = reg_create_key(hRootKey, subkey, &hKey, flag); + + if (ERROR_SUCCESS == lRet) + { + lRet = reg_set_string_value(hKey, value_name, data); + RegCloseKey(hKey); + } + return lRet; +} + + static LONG +register_inproc_server( + HKEY hRootKey, + const char *clsid, + const char *extname, + const char *module, + const char *threading_model, + DWORD flag) +{ + CHAR subkey[BUFSIZE]; + LONG lRet; + + sprintf(subkey, "CLSID\\%s", clsid); + lRet = reg_create_key_and_value(hRootKey, subkey, NULL, extname, flag); + if (ERROR_SUCCESS == lRet) + { + sprintf(subkey, "CLSID\\%s\\InProcServer32", clsid); + lRet = reg_create_key_and_value(hRootKey, subkey, NULL, module, flag); + if (ERROR_SUCCESS == lRet) + { + lRet = reg_create_key_and_value(hRootKey, subkey, + "ThreadingModel", threading_model, flag); + } + } + return lRet; +} + + static LONG +register_shellex( + HKEY hRootKey, + const char *clsid, + const char *name, + const char *exe_path, + DWORD flag) +{ + LONG lRet = reg_create_key_and_value( + hRootKey, + "*\\shellex\\ContextMenuHandlers\\gvim", + NULL, + clsid, + flag); + + if (ERROR_SUCCESS == lRet) + { + lRet = reg_create_key_and_value( + HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", + clsid, + name, + flag); + + if (ERROR_SUCCESS == lRet) + { + lRet = reg_create_key_and_value( + HKEY_LOCAL_MACHINE, + "Software\\Vim\\Gvim", + "path", + exe_path, + flag); + } + } + return lRet; +} + + static LONG +register_openwith( + HKEY hRootKey, + const char *exe_path, + DWORD flag) +{ + char exe_cmd[BUFSIZE]; + LONG lRet; + + sprintf(exe_cmd, "\"%s\" \"%%1\"", exe_path); + lRet = reg_create_key_and_value( + hRootKey, + "Applications\\gvim.exe\\shell\\edit\\command", + NULL, + exe_cmd, + flag); + + if (ERROR_SUCCESS == lRet) + { + int i; + static const char *openwith[] = { + ".htm\\OpenWithList\\gvim.exe", + ".vim\\OpenWithList\\gvim.exe", + "*\\OpenWithList\\gvim.exe", + }; + + for (i = 0; ERROR_SUCCESS == lRet && i < (int)ARRAYSIZE(openwith); i++) + lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag); + } + + return lRet; +} + + static LONG +register_uninstall( + HKEY hRootKey, + const char *appname, + const char *display_name, + const char *uninstall_string, + const char *display_icon, + const char *display_version, + const char *publisher) +{ + LONG lRet = reg_create_key_and_value(hRootKey, appname, + "DisplayName", display_name, KEY_WOW64_64KEY); + + if (ERROR_SUCCESS == lRet) + lRet = reg_create_key_and_value(hRootKey, appname, + "UninstallString", uninstall_string, KEY_WOW64_64KEY); + if (ERROR_SUCCESS == lRet) + lRet = reg_create_key_and_value(hRootKey, appname, + "DisplayIcon", display_icon, KEY_WOW64_64KEY); + if (ERROR_SUCCESS == lRet) + lRet = reg_create_key_and_value(hRootKey, appname, + "DisplayVersion", display_version, KEY_WOW64_64KEY); + if (ERROR_SUCCESS == lRet) + lRet = reg_create_key_and_value(hRootKey, appname, + "Publisher", publisher, KEY_WOW64_64KEY); + return lRet; +} + +/* + * Add some entries to the registry: + * - to add "Edit with Vim" to the context * menu + * - to add Vim to the "Open with..." list + * - to uninstall Vim + */ +//ARGSUSED + static int +install_registry(void) +{ + LONG lRet = ERROR_SUCCESS; + const char *vim_ext_ThreadingModel = "Apartment"; + const char *vim_ext_name = "Vim Shell Extension"; + const char *vim_ext_clsid = "{51EEE242-AD87-11d3-9C1E-0090278BBD99}"; + char vim_exe_path[MAX_PATH]; + char display_name[BUFSIZE]; + char uninstall_string[BUFSIZE]; + char icon_string[BUFSIZE]; + char version_string[BUFSIZE]; + int i; + int loop_count = is_64bit_os() ? 2 : 1; + DWORD flag; + + sprintf(vim_exe_path, "%s\\gvim.exe", installdir); + + if (install_popup) + { + char bufg[BUFSIZE]; + + printf("Creating \"Edit with Vim\" popup menu entry\n"); + + for (i = 0; i < loop_count; i++) + { + if (i == 0) + { + sprintf(bufg, "%s\\" GVIMEXT32_PATH, installdir); + flag = KEY_WOW64_32KEY; + } + else + { + sprintf(bufg, "%s\\" GVIMEXT64_PATH, installdir); + flag = KEY_WOW64_64KEY; + } + + lRet = register_inproc_server( + HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name, + bufg, vim_ext_ThreadingModel, flag); + if (ERROR_SUCCESS != lRet) + return FAIL; + lRet = register_shellex( + HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name, + vim_exe_path, flag); + if (ERROR_SUCCESS != lRet) + return FAIL; + } + } + + if (install_openwith) + { + printf("Creating \"Open with ...\" list entry\n"); + + for (i = 0; i < loop_count; i++) + { + if (i == 0) + flag = KEY_WOW64_32KEY; + else + flag = KEY_WOW64_64KEY; + + lRet = register_openwith(HKEY_CLASSES_ROOT, vim_exe_path, flag); + if (ERROR_SUCCESS != lRet) + return FAIL; + } + } + + printf("Creating an uninstall entry\n"); + sprintf(display_name, "Vim " VIM_VERSION_SHORT +#ifdef _M_ARM64 + " (arm64)" +#elif _M_X64 + " (x64)" +#endif + ); + + // For the NSIS installer use the generated uninstaller. + if (interactive) + sprintf(uninstall_string, "%s\\uninstall.exe", installdir); + else + sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir); + + sprintf(icon_string, "%s\\gvim.exe,0", installdir); + + sprintf(version_string, VIM_VERSION_SHORT "." VIM_VERSION_PATCHLEVEL_STR); + + lRet = register_uninstall( + HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT, + display_name, + uninstall_string, + icon_string, + version_string, + "Bram Moolenaar et al."); + if (ERROR_SUCCESS != lRet) + return FAIL; + + return OK; +} + + static void +change_popup_choice(int idx) +{ + if (install_popup == 0) + { + choices[idx].text = "Install an entry for Vim in the popup menu for the right\n mouse button so that you can edit any file with Vim"; + install_popup = 1; + } + else + { + choices[idx].text = "Do NOT install an entry for Vim in the popup menu for the\n right mouse button to edit any file with Vim"; + install_popup = 0; + } +} + +/* + * Only add the choice for the popup menu entry when gvim.exe was found and + * both gvimext.dll and regedit.exe exist. + */ + static void +init_popup_choice(void) +{ + struct stat st; + + if (has_gvim + && (stat(GVIMEXT32_PATH, &st) >= 0 + || stat(GVIMEXT64_PATH, &st) >= 0)) + { + choices[choice_count].changefunc = change_popup_choice; + choices[choice_count].installfunc = NULL; + choices[choice_count].active = 1; + change_popup_choice(choice_count); // set the text + ++choice_count; + } + else + add_dummy_choice(); +} + + static void +change_openwith_choice(int idx) +{ + if (install_openwith == 0) + { + choices[idx].text = "Add Vim to the \"Open With...\" list in the popup menu for the right\n mouse button so that you can edit any file with Vim"; + install_openwith = 1; + } + else + { + choices[idx].text = "Do NOT add Vim to the \"Open With...\" list in the popup menu for the\n right mouse button to edit any file with Vim"; + install_openwith = 0; + } +} + +/* + * Only add the choice for the open-with menu entry when gvim.exe was found + * and regedit.exe exist. + */ + static void +init_openwith_choice(void) +{ + if (has_gvim) + { + choices[choice_count].changefunc = change_openwith_choice; + choices[choice_count].installfunc = NULL; + choices[choice_count].active = 1; + change_openwith_choice(choice_count); // set the text + ++choice_count; + } + else + add_dummy_choice(); +} + +/* + * Create a shell link. + * + * returns 0 on failure, non-zero on successful completion. + * + * NOTE: Currently untested with mingw. + */ + int +create_shortcut( + const char *shortcut_name, + const char *iconfile_path, + int iconindex, + const char *shortcut_target, + const char *shortcut_args, + const char *workingdir + ) +{ + IShellLink *shelllink_ptr; + HRESULT hres; + IPersistFile *persistfile_ptr; + + // Initialize COM library + hres = CoInitialize(NULL); + if (!SUCCEEDED(hres)) + { + printf("Error: Could not open the COM library. Not creating shortcut.\n"); + return FAIL; + } + + // Instantiate a COM object for the ShellLink, store a pointer to it + // in shelllink_ptr. + hres = CoCreateInstance(&CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IShellLink, + (void **) &shelllink_ptr); + + if (SUCCEEDED(hres)) // If the instantiation was successful... + { + // ...Then build a PersistFile interface for the ShellLink so we can + // save it as a file after we build it. + hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr, + &IID_IPersistFile, (void **) &persistfile_ptr); + + if (SUCCEEDED(hres)) + { + wchar_t wsz[BUFSIZE]; + + // translate the (possibly) multibyte shortcut filename to windows + // Unicode so it can be used as a file name. + MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, sizeof(wsz)/sizeof(wsz[0])); + + // set the attributes + shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target); + shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr, + workingdir); + shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr, + iconfile_path, iconindex); + shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args); + + // save the shortcut to a file and return the PersistFile object + persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1); + persistfile_ptr->lpVtbl->Release(persistfile_ptr); + } + else + { + printf("QueryInterface Error\n"); + return FAIL; + } + + // Return the ShellLink object + shelllink_ptr->lpVtbl->Release(shelllink_ptr); + } + else + { + printf("CoCreateInstance Error - hres = %08x\n", (int)hres); + return FAIL; + } + + return OK; +} + +/* + * Build a path to where we will put a specified link. + * + * Return 0 on error, non-zero on success + */ + int +build_link_name( + char *link_path, + const char *link_name, + const char *shell_folder_name) +{ + char shell_folder_path[MAX_PATH]; + + if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL) + { + printf("An error occurred while attempting to find the path to %s.\n", + shell_folder_name); + return FAIL; + } + + // Make sure the directory exists (create Start Menu\Programs\Vim). + // Ignore errors if it already exists. + vim_mkdir(shell_folder_path, 0755); + + // build the path to the shortcut and the path to gvim.exe + sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name); + + return OK; +} + + static int +build_shortcut( + const char *name, // Name of the shortcut + const char *exename, // Name of the executable (e.g., vim.exe) + const char *args, + const char *shell_folder, + const char *workingdir) +{ + char executable_path[BUFSIZE]; + char link_name[BUFSIZE]; + + sprintf(executable_path, "%s\\%s", installdir, exename); + + if (build_link_name(link_name, name, shell_folder) == FAIL) + { + printf("An error has occurred. A shortcut to %s will not be created %s.\n", + name, + *shell_folder == 'd' ? "on the desktop" : "in the Start menu"); + return FAIL; + } + + // Create the shortcut: + return create_shortcut(link_name, executable_path, 0, + executable_path, args, workingdir); +} + +/* + * We used to use "homedir" as the working directory, but that is a bad choice + * on multi-user systems. However, not specifying a directory results in the + * current directory to be c:\Windows\system32 on Windows 7. Use environment + * variables instead. + */ +#define WORKDIR "%HOMEDRIVE%%HOMEPATH%" + +/* + * Create shortcut(s) in the Start Menu\Programs\Vim folder. + */ + static void +install_start_menu(int idx UNUSED) +{ + need_uninstall_entry = 1; + printf("Creating start menu\n"); + if (has_vim) + { + if (build_shortcut("Vim", "vim.exe", "", + VIM_STARTMENU, WORKDIR) == FAIL) + return; + if (build_shortcut("Vim Read-only", "vim.exe", "-R", + VIM_STARTMENU, WORKDIR) == FAIL) + return; + if (build_shortcut("Vim Diff", "vim.exe", "-d", + VIM_STARTMENU, WORKDIR) == FAIL) + return; + } + if (has_gvim) + { + if (build_shortcut("gVim", "gvim.exe", "", + VIM_STARTMENU, WORKDIR) == FAIL) + return; + if (build_shortcut("gVim Easy", "gvim.exe", "-y", + VIM_STARTMENU, WORKDIR) == FAIL) + return; + if (build_shortcut("gVim Read-only", "gvim.exe", "-R", + VIM_STARTMENU, WORKDIR) == FAIL) + return; + if (build_shortcut("gVim Diff", "gvim.exe", "-d", + VIM_STARTMENU, WORKDIR) == FAIL) + return; + } + if (build_shortcut("Uninstall", + interactive ? "uninstall.exe" : "uninstall-gui.exe", "", + VIM_STARTMENU, installdir) == FAIL) + return; + // For Windows NT the working dir of the vimtutor.bat must be right, + // otherwise gvim.exe won't be found and using gvimbat doesn't work. + if (build_shortcut("Vim tutor", "vimtutor.bat", "", + VIM_STARTMENU, installdir) == FAIL) + return; + if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h", + VIM_STARTMENU, WORKDIR) == FAIL) + return; + { + char shell_folder_path[BUFSIZE]; + + // Creating the URL shortcut works a bit differently... + if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL) + { + printf("Finding the path of the Start menu failed\n"); + return ; + } + add_pathsep(shell_folder_path); + strcat(shell_folder_path, "Vim Online.url"); + if (!WritePrivateProfileString("InternetShortcut", "URL", + "https://www.vim.org/", shell_folder_path)) + { + printf("Creating the Vim online URL failed\n"); + return; + } + } +} + + static void +toggle_startmenu_choice(int idx) +{ + if (choices[idx].installfunc == NULL) + { + choices[idx].installfunc = install_start_menu; + choices[idx].text = "Add Vim to the Start menu"; + } + else + { + choices[idx].installfunc = NULL; + choices[idx].text = "Do NOT add Vim to the Start menu"; + } +} + +/* + * Function to actually create the shortcuts + * + * Currently I am supplying no working directory to the shortcut. This + * means that the initial working dir will be: + * - the location of the shortcut if no file is supplied + * - the location of the file being edited if a file is supplied (ie via + * drag and drop onto the shortcut). + */ + void +install_shortcut_gvim(int idx) +{ + // Create shortcut(s) on the desktop + if (choices[idx].arg) + { + (void)build_shortcut(icon_names[0], "gvim.exe", + "", "desktop", WORKDIR); + need_uninstall_entry = 1; + } +} + + void +install_shortcut_evim(int idx) +{ + if (choices[idx].arg) + { + (void)build_shortcut(icon_names[1], "gvim.exe", + "-y", "desktop", WORKDIR); + need_uninstall_entry = 1; + } +} + + void +install_shortcut_gview(int idx) +{ + if (choices[idx].arg) + { + (void)build_shortcut(icon_names[2], "gvim.exe", + "-R", "desktop", WORKDIR); + need_uninstall_entry = 1; + } +} + + void +toggle_shortcut_choice(int idx) +{ + char *arg; + + if (choices[idx].installfunc == install_shortcut_gvim) + arg = "gVim"; + else if (choices[idx].installfunc == install_shortcut_evim) + arg = "gVim Easy"; + else + arg = "gVim Read-only"; + if (choices[idx].arg) + { + choices[idx].arg = 0; + alloc_text(idx, "Do NOT create a desktop icon for %s", arg); + } + else + { + choices[idx].arg = 1; + alloc_text(idx, "Create a desktop icon for %s", arg); + } +} + + static void +init_startmenu_choice(void) +{ + // Start menu + choices[choice_count].changefunc = toggle_startmenu_choice; + choices[choice_count].installfunc = NULL; + choices[choice_count].active = 1; + toggle_startmenu_choice(choice_count); // set the text + ++choice_count; +} + +/* + * Add the choice for the desktop shortcuts. + */ + static void +init_shortcut_choices(void) +{ + // Shortcut to gvim + choices[choice_count].text = NULL; + choices[choice_count].arg = 0; + choices[choice_count].active = has_gvim; + choices[choice_count].changefunc = toggle_shortcut_choice; + choices[choice_count].installfunc = install_shortcut_gvim; + toggle_shortcut_choice(choice_count); + ++choice_count; + + // Shortcut to evim + choices[choice_count].text = NULL; + choices[choice_count].arg = 0; + choices[choice_count].active = has_gvim; + choices[choice_count].changefunc = toggle_shortcut_choice; + choices[choice_count].installfunc = install_shortcut_evim; + toggle_shortcut_choice(choice_count); + ++choice_count; + + // Shortcut to gview + choices[choice_count].text = NULL; + choices[choice_count].arg = 0; + choices[choice_count].active = has_gvim; + choices[choice_count].changefunc = toggle_shortcut_choice; + choices[choice_count].installfunc = install_shortcut_gview; + toggle_shortcut_choice(choice_count); + ++choice_count; +} + +/* + * Attempt to register OLE for Vim. + */ + static void +install_OLE_register(void) +{ + char register_command_string[BUFSIZE + 30]; + + printf("\n--- Attempting to register Vim with OLE ---\n"); + printf("(There is no message whether this works or not.)\n"); + + sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir); + system(register_command_string); +} + +/* + * Remove the last part of directory "path[]" to get its parent, and put the + * result in "to[]". + */ + static void +dir_remove_last(const char *path, char to[MAX_PATH]) +{ + char c; + long last_char_to_copy; + long path_length = strlen(path); + + // skip the last character just in case it is a '\\' + last_char_to_copy = path_length - 2; + c = path[last_char_to_copy]; + + while (c != '\\') + { + last_char_to_copy--; + c = path[last_char_to_copy]; + } + + strncpy(to, path, (size_t)last_char_to_copy); + to[last_char_to_copy] = NUL; +} + + static void +set_directories_text(int idx) +{ + int vimfiles_dir_choice = choices[idx].arg; + + if (vimfiles_dir_choice == (int)vimfiles_dir_none) + alloc_text(idx, "Do NOT create plugin directories%s", ""); + else + alloc_text(idx, "Create plugin directories: %s", + vimfiles_dir_choices[vimfiles_dir_choice]); +} + +/* + * To get the "real" home directory: + * - get value of $HOME + * - if not found, get value of $HOMEDRIVE$HOMEPATH + * - if not found, get value of $USERPROFILE + * + * This code is based on init_homedir() in misc1.c, keep in sync! + */ +static char *homedir = NULL; + + void +init_homedir(void) +{ + char *var; + char buf[MAX_PATH]; + + if (homedir != NULL) + { + free(homedir); + homedir = NULL; + } + + var = getenv("HOME"); + + /* + * Typically, $HOME is not defined on Windows, unless the user has + * specifically defined it for Vim's sake. However, on Windows NT + * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for + * each user. Try constructing $HOME from these. + */ + if (var == NULL || *var == NUL) + { + char *homedrive, *homepath; + + homedrive = getenv("HOMEDRIVE"); + homepath = getenv("HOMEPATH"); + if (homepath == NULL || *homepath == NUL) + homepath = "\\"; + if (homedrive != NULL + && strlen(homedrive) + strlen(homepath) < sizeof(buf)) + { + sprintf(buf, "%s%s", homedrive, homepath); + if (buf[0] != NUL) + var = buf; + } + } + + if (var == NULL) + var = getenv("USERPROFILE"); + + /* + * Weird but true: $HOME may contain an indirect reference to another + * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set + * when $HOME is being set. + */ + if (var != NULL && *var == '%') + { + char *p; + char *exp; + + p = strchr(var + 1, '%'); + if (p != NULL) + { + strncpy(buf, var + 1, p - (var + 1)); + buf[p - (var + 1)] = NUL; + exp = getenv(buf); + if (exp != NULL && *exp != NUL + && strlen(exp) + strlen(p) < sizeof(buf)) + { + sprintf(buf, "%s%s", exp, p + 1); + var = buf; + } + } + } + + if (var != NULL && *var == NUL) // empty is same as not set + var = NULL; + + if (var == NULL) + homedir = NULL; + else + homedir = _strdup(var); +} + +/* + * Change the directory that the vim plugin directories will be created in: + * $HOME, $VIM or nowhere. + */ + static void +change_directories_choice(int idx) +{ + int choice_count = TABLE_SIZE(vimfiles_dir_choices); + + // Don't offer the $HOME choice if $HOME isn't set. + if (homedir == NULL) + --choice_count; + choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count); + set_directories_text(idx); +} + +/* + * Create the plugin directories... + */ +//ARGSUSED + static void +install_vimfilesdir(int idx) +{ + int i; + int vimfiles_dir_choice = choices[idx].arg; + char *p; + char vimdir_path[MAX_PATH]; + char vimfiles_path[MAX_PATH + 9]; + char tmp_dirname[BUFSIZE]; + + // switch on the location that the user wants the plugin directories + // built in + switch (vimfiles_dir_choice) + { + case vimfiles_dir_vim: + { + // Go to the %VIM% directory - check env first, then go one dir + // below installdir if there is no %VIM% environment variable. + // The accuracy of $VIM is checked in inspect_system(), so we + // can be sure it is ok to use here. + p = getenv("VIM"); + if (p == NULL) // No $VIM in path + dir_remove_last(installdir, vimdir_path); + else + strcpy(vimdir_path, p); + break; + } + case vimfiles_dir_home: + { + // Find the $HOME directory. Its existence was already checked. + p = homedir; + if (p == NULL) + { + printf("Internal error: $HOME is NULL\n"); + p = "c:\\"; + } + strcpy(vimdir_path, p); + break; + } + case vimfiles_dir_none: + { + // Do not create vim plugin directory. + return; + } + } + + // Now, just create the directory. If it already exists, it will fail + // silently. + sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path); + vim_mkdir(vimfiles_path, 0755); + + printf("Creating the following directories in \"%s\":\n", vimfiles_path); + for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++) + { + sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]); + printf(" %s", vimfiles_subdirs[i]); + vim_mkdir(tmp_dirname, 0755); + } + printf("\n"); +} + +/* + * Add the creation of runtime files to the setup sequence. + */ + static void +init_directories_choice(void) +{ + struct stat st; + char tmp_dirname[BUFSIZE]; + char *p; + int vimfiles_dir_choice; + + choices[choice_count].text = alloc(150); + choices[choice_count].changefunc = change_directories_choice; + choices[choice_count].installfunc = install_vimfilesdir; + choices[choice_count].active = 1; + + // Check if the "compiler" directory already exists. That's a good + // indication that the plugin directories were already created. + p = getenv("HOME"); + if (p != NULL) + { + vimfiles_dir_choice = (int)vimfiles_dir_home; + sprintf(tmp_dirname, "%s\\vimfiles\\compiler", p); + if (stat(tmp_dirname, &st) == 0) + vimfiles_dir_choice = (int)vimfiles_dir_none; + } + else + { + vimfiles_dir_choice = (int)vimfiles_dir_vim; + p = getenv("VIM"); + if (p == NULL) // No $VIM in path, use the install dir. + dir_remove_last(installdir, tmp_dirname); + else + strcpy(tmp_dirname, p); + strcat(tmp_dirname, "\\vimfiles\\compiler"); + if (stat(tmp_dirname, &st) == 0) + vimfiles_dir_choice = (int)vimfiles_dir_none; + } + + choices[choice_count].arg = vimfiles_dir_choice; + set_directories_text(choice_count); + ++choice_count; +} + +/* + * Setup the choices and the default values. + */ + static void +setup_choices(void) +{ + // install the batch files + init_bat_choices(); + + // (over) write _vimrc file + init_vimrc_choices(); + + // Whether to add Vim to the popup menu + init_popup_choice(); + + // Whether to add Vim to the "Open With..." menu + init_openwith_choice(); + + // Whether to add Vim to the Start Menu. + init_startmenu_choice(); + + // Whether to add shortcuts to the Desktop. + init_shortcut_choices(); + + // Whether to create the runtime directories. + init_directories_choice(); +} + + static void +print_cmd_line_help(void) +{ + printf("Vim installer non-interactive command line arguments:\n"); + printf("\n"); + printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n"); + printf(" Create .bat files for Vim variants in the Windows directory.\n"); + printf("-create-vimrc\n"); + printf(" Create a default _vimrc file if one does not already exist.\n"); + printf("-vimrc-remap [no|win]\n"); + printf(" Remap keys when creating a default _vimrc file.\n"); + printf("-vimrc-behave [unix|mswin|default]\n"); + printf(" Set mouse behavior when creating a default _vimrc file.\n"); + printf("-vimrc-compat [vi|vim|defaults|all]\n"); + printf(" Set Vi compatibility when creating a default _vimrc file.\n"); + printf("-install-popup\n"); + printf(" Install the Edit-with-Vim context menu entry\n"); + printf("-install-openwith\n"); + printf(" Add Vim to the \"Open With...\" context menu list\n"); + printf("-add-start-menu"); + printf(" Add Vim to the start menu\n"); + printf("-install-icons"); + printf(" Create icons for gVim executables on the desktop\n"); + printf("-create-directories [vim|home]\n"); + printf(" Create runtime directories to drop plugins into; in the $VIM\n"); + printf(" or $HOME directory\n"); + printf("-register-OLE"); + printf(" Ignored\n"); + printf("\n"); +} + +/* + * Setup installation choices based on command line switches + */ + static void +command_line_setup_choices(int argc, char **argv) +{ + int i, j; + + for (i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-create-batfiles") == 0) + { + if (i + 1 == argc) + continue; + while (argv[i + 1][0] != '-' && i < argc) + { + i++; + for (j = 1; j < TARGET_COUNT; ++j) + if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim) + && strcmp(argv[i], targets[j].name) == 0) + { + init_bat_choice(j); + break; + } + if (j == TARGET_COUNT) + printf("%s is not a valid choice for -create-batfiles\n", + argv[i]); + + if (i + 1 == argc) + break; + } + } + else if (strcmp(argv[i], "-create-vimrc") == 0) + { + // Setup default vimrc choices. If there is already a _vimrc file, + // it will NOT be overwritten. + init_vimrc_choices(); + } + else if (strcmp(argv[i], "-vimrc-remap") == 0) + { + if (i + 1 == argc) + break; + i++; + if (strcmp(argv[i], "no") == 0) + remap_choice = remap_no; + else if (strcmp(argv[i], "win") == 0) + remap_choice = remap_win; + } + else if (strcmp(argv[i], "-vimrc-behave") == 0) + { + if (i + 1 == argc) + break; + i++; + if (strcmp(argv[i], "unix") == 0) + mouse_choice = mouse_xterm; + else if (strcmp(argv[i], "mswin") == 0) + mouse_choice = mouse_mswin; + else if (strcmp(argv[i], "default") == 0) + mouse_choice = mouse_default; + } + else if (strcmp(argv[i], "-vimrc-compat") == 0) + { + if (i + 1 == argc) + break; + i++; + if (strcmp(argv[i], "vi") == 0) + compat_choice = compat_vi; + else if (strcmp(argv[i], "vim") == 0) + compat_choice = compat_vim; + else if (strcmp(argv[i], "defaults") == 0) + compat_choice = compat_some_enhancements; + else if (strcmp(argv[i], "all") == 0) + compat_choice = compat_all_enhancements; + } + else if (strcmp(argv[i], "-install-popup") == 0) + { + init_popup_choice(); + } + else if (strcmp(argv[i], "-install-openwith") == 0) + { + init_openwith_choice(); + } + else if (strcmp(argv[i], "-add-start-menu") == 0) + { + init_startmenu_choice(); + } + else if (strcmp(argv[i], "-install-icons") == 0) + { + init_shortcut_choices(); + } + else if (strcmp(argv[i], "-create-directories") == 0) + { + int vimfiles_dir_choice = (int)vimfiles_dir_none; + + init_directories_choice(); + if (i + 1 < argc && argv[i + 1][0] != '-') + { + i++; + if (strcmp(argv[i], "vim") == 0) + vimfiles_dir_choice = (int)vimfiles_dir_vim; + else if (strcmp(argv[i], "home") == 0) + { + if (homedir == NULL) // No $HOME in environment + vimfiles_dir_choice = (int)vimfiles_dir_none; + else + vimfiles_dir_choice = (int)vimfiles_dir_home; + } + else + { + printf("Unknown argument for -create-directories: %s\n", + argv[i]); + print_cmd_line_help(); + } + } + else // No choice specified, default to vim directory + vimfiles_dir_choice = (int)vimfiles_dir_vim; + choices[choice_count - 1].arg = vimfiles_dir_choice; + } + else if (strcmp(argv[i], "-register-OLE") == 0) + { + // This is always done when gvim is found + } + else // Unknown switch + { + printf("Got unknown argument argv[%d] = %s\n", i, argv[i]); + print_cmd_line_help(); + } + } +} + + +/* + * Show a few screens full of helpful information. + */ + static void +show_help(void) +{ + static char *(items[]) = + { +"Installing .bat files\n" +"---------------------\n" +"The vim.bat file is written in one of the directories in $PATH.\n" +"This makes it possible to start Vim from the command line.\n" +"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n" +"present. It is assumed you will use the existing vim.exe.\n" +"If vim.bat can already be found in $PATH this is probably for an old\n" +"version of Vim (but this is not checked!). You can overwrite it.\n" +"If no vim.bat already exists, you can select one of the directories in\n" +"$PATH for creating the batch file, or disable creating a vim.bat file.\n" +"\n" +"If you choose not to create the vim.bat file, Vim can still be executed\n" +"in other ways, but not from the command line.\n" +"\n" +"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n" +"The first item can be used to change the path for all of them.\n" +, +"Creating a _vimrc file\n" +"----------------------\n" +"The _vimrc file is used to set options for how Vim behaves.\n" +"The install program can create a _vimrc file with a few basic choices.\n" +"You can edit this file later to tune your preferences.\n" +"If you already have a _vimrc or .vimrc file it can be overwritten.\n" +"Don't do that if you have made changes to it.\n" +, +"Vim features\n" +"------------\n" +"(this choice is only available when creating a _vimrc file)\n" +"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n" +" disabled. Only choose Vi-compatible if you really need full Vi\n" +" compatibility.\n" +"2. Vim runs in not-Vi-compatible mode. Vim is still mostly Vi compatible,\n" +" but adds nice features like multi-level undo.\n" +"3. Running Vim with some enhancements is useful when you want some of\n" +" the nice Vim features, but have a slow computer and want to keep it\n" +" really fast.\n" +"4. Syntax highlighting shows many files in color. Not only does this look\n" +" nice, it also makes it easier to spot errors and you can work faster.\n" +" The other features include editing compressed files.\n" +, +"Windows key mapping\n" +"-------------------\n" +"(this choice is only available when creating a _vimrc file)\n" +"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n" +"pastes text from the clipboard. There are a few more keys like these.\n" +"Unfortunately, in Vim these keys normally have another meaning.\n" +"1. Choose to have the keys like they normally are in Vim (useful if you\n" +" also use Vim on other systems).\n" +"2. Choose to have the keys work like they are used on MS-Windows (useful\n" +" if you mostly work on MS-Windows).\n" +, +"Mouse use\n" +"---------\n" +"(this choice is only available when creating a _vimrc file)\n" +"The right mouse button can be used in two ways:\n" +"1. The Unix way is to extend an existing selection. The popup menu is\n" +" not available.\n" +"2. The MS-Windows way is to show a popup menu, which allows you to\n" +" copy/paste text, undo/redo, etc. Extending the selection can still be\n" +" done by keeping SHIFT pressed while using the left mouse button\n" +, +"Edit-with-Vim context menu entry\n" +"--------------------------------\n" +"(this choice is only available when gvim.exe and gvimext.dll are present)\n" +"You can associate different file types with Vim, so that you can (double)\n" +"click on a file to edit it with Vim. This means you have to individually\n" +"select each file type.\n" +"An alternative is the option offered here: Install an \"Edit with Vim\"\n" +"entry in the popup menu for the right mouse button. This means you can\n" +"edit any file with Vim.\n" +, +"\"Open With...\" context menu entry\n" +"--------------------------------\n" +"(this choice is only available when gvim.exe is present)\n" +"This option adds Vim to the \"Open With...\" entry in the popup menu for\n" +"the right mouse button. This also makes it possible to edit HTML files\n" +"directly from Internet Explorer.\n" +, +"Add Vim to the Start menu\n" +"-------------------------\n" +"In Windows 95 and later, Vim can be added to the Start menu. This will\n" +"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n" +, +"Icons on the desktop\n" +"--------------------\n" +"(these choices are only available when installing gvim)\n" +"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n" +, +"Create plugin directories\n" +"-------------------------\n" +"Plugin directories allow extending Vim by dropping a file into a directory.\n" +"This choice allows creating them in $HOME (if you have a home directory) or\n" +"$VIM (used for everybody on the system).\n" +, +NULL + }; + int i; + int c; + + rewind(stdin); + printf("\n"); + for (i = 0; items[i] != NULL; ++i) + { + puts(items[i]); + printf("Hit Enter to continue, b (back) or q (quit help): "); + c = getchar(); + rewind(stdin); + if (c == 'b' || c == 'B') + { + if (i == 0) + --i; + else + i -= 2; + } + if (c == 'q' || c == 'Q') + break; + printf("\n"); + } +} + +/* + * Install the choices. + */ + static void +install(void) +{ + int i; + + // Install the selected choices. + for (i = 0; i < choice_count; ++i) + if (choices[i].installfunc != NULL && choices[i].active) + (choices[i].installfunc)(i); + + // Add some entries to the registry, if needed. + if (install_popup + || install_openwith + || (need_uninstall_entry && interactive) + || !interactive) + install_registry(); + + // Register gvim with OLE. + if (has_gvim) + install_OLE_register(); +} + +/* + * request_choice + */ + static void +request_choice(void) +{ + int i; + + printf("\n\nInstall will do for you:\n"); + for (i = 0; i < choice_count; ++i) + if (choices[i].active) + printf("%2d %s\n", i + 1, choices[i].text); + printf("To change an item, enter its number\n\n"); + printf("Enter item number, h (help), d (do it) or q (quit): "); +} + + int +main(int argc, char **argv) +{ + int i; + char buf[BUFSIZE]; + + /* + * Run interactively if there are no command line arguments. + */ + if (argc > 1) + interactive = 0; + else + interactive = 1; + + // Initialize this program. + do_inits(argv); + init_homedir(); + + if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0) + { + // Only check for already installed Vims. Used by NSIS installer. + i = uninstall_check(1); + + // Find the value of $VIM, because NSIS isn't able to do this by + // itself. + get_vim_env(); + + // When nothing found exit quietly. If something found wait for + // a little while, so that the user can read the messages. + if (i && _isatty(1)) + sleep(3); + exit(0); + } + + printf("This program sets up the installation of Vim " + VIM_VERSION_MEDIUM "\n\n"); + + // Check if the user unpacked the archives properly. + check_unpack(); + + // Check for already installed Vims. + if (interactive) + uninstall_check(0); + + // Find out information about the system. + inspect_system(); + + if (interactive) + { + // Setup all the choices. + setup_choices(); + + // Let the user change choices and finally install (or quit). + for (;;) + { + request_choice(); + rewind(stdin); + if (scanf("%99s", buf) == 1) + { + if (isdigit(buf[0])) + { + // Change a choice. + i = atoi(buf); + if (i > 0 && i <= choice_count && choices[i - 1].active) + (choices[i - 1].changefunc)(i - 1); + else + printf("\nIllegal choice\n"); + } + else if (buf[0] == 'h' || buf[0] == 'H') + { + // Help + show_help(); + } + else if (buf[0] == 'd' || buf[0] == 'D') + { + // Install! + install(); + printf("\nThat finishes the installation. Happy Vimming!\n"); + break; + } + else if (buf[0] == 'q' || buf[0] == 'Q') + { + // Quit + printf("\nExiting without anything done\n"); + break; + } + else + printf("\nIllegal choice\n"); + } + } + printf("\n"); + myexit(0); + } + else + { + /* + * Run non-interactive - setup according to the command line switches + */ + command_line_setup_choices(argc, argv); + install(); + + // Avoid that the user has to hit Enter, just wait a little bit to + // allow reading the messages. + sleep(2); + } + + return 0; +} diff --git a/src/dosinst.h b/src/dosinst.h new file mode 100644 index 0000000..f1d3dc6 --- /dev/null +++ b/src/dosinst.h @@ -0,0 +1,516 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ +/* + * dosinst.h: Common code for dosinst.c and uninstall.c + */ + +#include +#include +#include +#include +#include + +#ifndef UNIX_LINT +# include +# include + +# include + +# include +# include +#endif + +#ifdef UNIX_LINT +// Running lint on Unix: Some things are missing. +char *searchpath(char *name); +#endif + +#if defined(UNIX_LINT) +# include +# include +#endif + +#include "version.h" + +#if defined(UNIX_LINT) +# define vim_mkdir(x, y) mkdir((char *)(x), y) +#else +# define vim_mkdir(x, y) _mkdir((char *)(x)) +#endif + +#define sleep(n) Sleep((n) * 1000) + +// ---------------------------------------- + + +#define BUFSIZE (MAX_PATH*2) // long enough to hold a file name path +#define NUL 0 + +#define FAIL 0 +#define OK 1 + +#ifndef FALSE +# define FALSE 0 +#endif +#ifndef TRUE +# define TRUE 1 +#endif + +/* + * Modern way of creating registry entries, also works on 64 bit windows when + * compiled as a 32 bit program. + */ +# ifndef KEY_WOW64_64KEY +# define KEY_WOW64_64KEY 0x0100 +# endif +# ifndef KEY_WOW64_32KEY +# define KEY_WOW64_32KEY 0x0200 +# endif + +#ifdef __MINGW32__ +# define UNUSED __attribute__((unused)) +#else +# define UNUSED +#endif + +#define VIM_STARTMENU "Programs\\Vim " VIM_VERSION_SHORT + +int interactive; // non-zero when running interactively + +/* + * Call malloc() and exit when out of memory. + */ + static void * +alloc(int len) +{ + void *p; + + p = malloc(len); + if (p == NULL) + { + printf("ERROR: out of memory\n"); + exit(1); + } + return p; +} + +/* + * The toupper() in Bcc 5.5 doesn't work, use our own implementation. + */ + static int +mytoupper(int c) +{ + if (c >= 'a' && c <= 'z') + return c - 'a' + 'A'; + return c; +} + + static void +myexit(int n) +{ + if (!interactive) + { + // Present a prompt, otherwise error messages can't be read. + printf("Press Enter to continue\n"); + rewind(stdin); + (void)getchar(); + } + exit(n); +} + + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL); +/* + * Check if this is a 64-bit OS. + */ + static BOOL +is_64bit_os(void) +{ +#ifdef _WIN64 + return TRUE; +#else + BOOL bIsWow64 = FALSE; + LPFN_ISWOW64PROCESS pIsWow64Process; + + pIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( + GetModuleHandle("kernel32"), "IsWow64Process"); + if (pIsWow64Process != NULL) + pIsWow64Process(GetCurrentProcess(), &bIsWow64); + return bIsWow64; +#endif +} + + static char * +searchpath(char *name) +{ + static char widename[2 * BUFSIZE]; + static char location[2 * BUFSIZE + 2]; + + // There appears to be a bug in FindExecutableA() on Windows NT. + // Use FindExecutableW() instead... + MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)name, -1, + (LPWSTR)widename, BUFSIZE); + if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"", + (LPWSTR)location) > (HINSTANCE)32) + { + WideCharToMultiByte(CP_ACP, 0, (LPWSTR)location, -1, + (LPSTR)widename, 2 * BUFSIZE, NULL, NULL); + return widename; + } + return NULL; +} + +/* + * Call searchpath() and save the result in allocated memory, or return NULL. + */ + static char * +searchpath_save(char *name) +{ + char *p; + char *s; + + p = searchpath(name); + if (p == NULL) + return NULL; + s = alloc(strlen(p) + 1); + strcpy(s, p); + return s; +} + + +#ifndef CSIDL_COMMON_PROGRAMS +# define CSIDL_COMMON_PROGRAMS 0x0017 +#endif +#ifndef CSIDL_COMMON_DESKTOPDIRECTORY +# define CSIDL_COMMON_DESKTOPDIRECTORY 0x0019 +#endif + +/* + * Get the path to a requested Windows shell folder. + * + * Return FAIL on error, OK on success + */ + int +get_shell_folder_path( + char *shell_folder_path, + const char *shell_folder_name) +{ + /* + * The following code was successfully built with make_mvc.mak. + * The resulting executable worked on Windows 95, Millennium Edition, and + * 2000 Professional. But it was changed after testing... + */ + LPITEMIDLIST pidl = 0; // Pointer to an Item ID list allocated below + LPMALLOC pMalloc; // Pointer to an IMalloc interface + int csidl; + int alt_csidl = -1; + static int desktop_csidl = -1; + static int programs_csidl = -1; + int *pcsidl; + int r; + + if (strcmp(shell_folder_name, "desktop") == 0) + { + pcsidl = &desktop_csidl; + csidl = CSIDL_COMMON_DESKTOPDIRECTORY; + alt_csidl = CSIDL_DESKTOP; + } + else if (strncmp(shell_folder_name, "Programs", 8) == 0) + { + pcsidl = &programs_csidl; + csidl = CSIDL_COMMON_PROGRAMS; + alt_csidl = CSIDL_PROGRAMS; + } + else + { + printf("\nERROR (internal) unrecognised shell_folder_name: \"%s\"\n\n", + shell_folder_name); + return FAIL; + } + + // Did this stuff before, use the same ID again. + if (*pcsidl >= 0) + { + csidl = *pcsidl; + alt_csidl = -1; + } + +retry: + // Initialize pointer to IMalloc interface + if (NOERROR != SHGetMalloc(&pMalloc)) + { + printf("\nERROR getting interface for shell_folder_name: \"%s\"\n\n", + shell_folder_name); + return FAIL; + } + + // Get an ITEMIDLIST corresponding to the folder code + if (NOERROR != SHGetSpecialFolderLocation(0, csidl, &pidl)) + { + if (alt_csidl < 0 || NOERROR != SHGetSpecialFolderLocation(0, + alt_csidl, &pidl)) + { + printf("\nERROR getting ITEMIDLIST for shell_folder_name: \"%s\"\n\n", + shell_folder_name); + return FAIL; + } + csidl = alt_csidl; + alt_csidl = -1; + } + + // Translate that ITEMIDLIST to a string + r = SHGetPathFromIDList(pidl, shell_folder_path); + + // Free the data associated with pidl + pMalloc->lpVtbl->Free(pMalloc, pidl); + // Release the IMalloc interface + pMalloc->lpVtbl->Release(pMalloc); + + if (!r) + { + if (alt_csidl >= 0) + { + // We probably get here for Windows 95: the "all users" + // desktop/start menu entry doesn't exist. + csidl = alt_csidl; + alt_csidl = -1; + goto retry; + } + printf("\nERROR translating ITEMIDLIST for shell_folder_name: \"%s\"\n\n", + shell_folder_name); + return FAIL; + } + + // If there is an alternative: verify we can write in this directory. + // This should cause a retry when the "all users" directory exists but we + // are a normal user and can't write there. + if (alt_csidl >= 0) + { + char tbuf[BUFSIZE]; + FILE *fd; + + strcpy(tbuf, shell_folder_path); + strcat(tbuf, "\\vim write test"); + fd = fopen(tbuf, "w"); + if (fd == NULL) + { + csidl = alt_csidl; + alt_csidl = -1; + goto retry; + } + fclose(fd); + unlink(tbuf); + } + + /* + * Keep the found csidl for next time, so that we don't have to do the + * write test every time. + */ + if (*pcsidl < 0) + *pcsidl = csidl; + + if (strncmp(shell_folder_name, "Programs\\", 9) == 0) + strcat(shell_folder_path, shell_folder_name + 8); + + return OK; +} + +/* + * List of targets. The first one (index zero) is used for the default path + * for the batch files. + */ +#define TARGET_COUNT 9 + +struct +{ + char *name; // Vim exe name (without .exe) + char *batname; // batch file name + char *lnkname; // shortcut file name + char *exename; // exe file name + char *exenamearg; // exe file name when using exearg + char *exearg; // argument for vim.exe or gvim.exe + char *oldbat; // path to existing xxx.bat or NULL + char *oldexe; // path to existing xxx.exe or NULL + char batpath[BUFSIZE]; // path of batch file to create; not + // created when it's empty +} targets[TARGET_COUNT] = +{ + {"all", "batch files", NULL, NULL, NULL, NULL, NULL, NULL, ""}, + {"vim", "vim.bat", "Vim.lnk", + "vim.exe", "vim.exe", "", NULL, NULL, ""}, + {"gvim", "gvim.bat", "gVim.lnk", + "gvim.exe", "gvim.exe", "", NULL, NULL, ""}, + {"evim", "evim.bat", "gVim Easy.lnk", + "evim.exe", "gvim.exe", "-y", NULL, NULL, ""}, + {"view", "view.bat", "Vim Read-only.lnk", + "view.exe", "vim.exe", "-R", NULL, NULL, ""}, + {"gview", "gview.bat", "gVim Read-only.lnk", + "gview.exe", "gvim.exe", "-R", NULL, NULL, ""}, + {"vimdiff", "vimdiff.bat", "Vim Diff.lnk", + "vimdiff.exe","vim.exe", "-d", NULL, NULL, ""}, + {"gvimdiff","gvimdiff.bat", "gVim Diff.lnk", + "gvimdiff.exe","gvim.exe", "-d", NULL, NULL, ""}, + {"vimtutor","vimtutor.bat", "Vim tutor.lnk", + "vimtutor.bat", "vimtutor.bat", "", NULL, NULL, ""}, +}; + +/* Uninstall key for vim.bat, etc. */ +#define VIMBAT_UNINSTKEY "rem # uninstall key: " VIM_VERSION_NODOT " #" + +#define ICON_COUNT 3 +char *(icon_names[ICON_COUNT]) = + {"gVim " VIM_VERSION_SHORT, + "gVim Easy " VIM_VERSION_SHORT, + "gVim Read only " VIM_VERSION_SHORT}; +char *(icon_link_names[ICON_COUNT]) = + {"gVim " VIM_VERSION_SHORT ".lnk", + "gVim Easy " VIM_VERSION_SHORT ".lnk", + "gVim Read only " VIM_VERSION_SHORT ".lnk"}; + +/* This is only used for dosinst.c. */ +#if defined(DOSINST) +/* + * Run an external command and wait for it to finish. + */ + static void +run_command(char *cmd) +{ + char *cmd_path; + char cmd_buf[BUFSIZE * 2 + 35]; + char *p; + + // On WinNT, 'start' is a shell built-in for cmd.exe rather than an + // executable (start.exe) like in Win9x. + cmd_path = searchpath_save("cmd.exe"); + if (cmd_path != NULL) + { + // There is a cmd.exe, so this might be Windows NT. If it is, + // we need to call cmd.exe explicitly. If it is a later OS, + // calling cmd.exe won't hurt if it is present. + // Also, "start" on NT expects a window title argument. + // Replace the slashes with backslashes. + while ((p = strchr(cmd_path, '/')) != NULL) + *p = '\\'; + sprintf(cmd_buf, "%s /c start \"vimcmd\" /wait %s", cmd_path, cmd); + free(cmd_path); + } + else + { + // No cmd.exe, just make the call and let the system handle it. + sprintf(cmd_buf, "start /w %s", cmd); + } + system(cmd_buf); +} +#endif + +/* + * Append a backslash to "name" if there isn't one yet. + */ + void +add_pathsep(char *name) +{ + int len = strlen(name); + + if (len > 0 && name[len - 1] != '\\' && name[len - 1] != '/') + strcat(name, "\\"); +} + +/* + * The normal chdir() does not change the default drive. This one does. + */ + int +change_drive(int drive) +{ + char temp[3] = "-:"; + temp[0] = (char)(drive + 'A' - 1); + return !SetCurrentDirectory(temp); +} + +/* + * Change directory to "path". + * Return 0 for success, -1 for failure. + */ + int +mch_chdir(char *path) +{ + if (path[0] == NUL) // just checking... + return 0; + if (path[1] == ':') // has a drive name + { + if (change_drive(mytoupper(path[0]) - 'A' + 1)) + return -1; // invalid drive name + path += 2; + } + if (*path == NUL) // drive name only + return 0; + return chdir(path); // let the normal chdir() do the rest +} + +/* + * Expand the executable name into a full path name. + */ + static char * +my_fullpath(char *buf, char *fname UNUSED, int len) +{ + // Only GetModuleFileName() will get the long file name path. + // GetFullPathName() may still use the short (FAT) name. + DWORD len_read = GetModuleFileName(NULL, buf, (size_t)len); + + return (len_read > 0 && len_read < (DWORD)len) ? buf : NULL; +} + +/* + * Remove the tail from a file or directory name. + * Puts a NUL on the last '/' or '\'. + */ + static void +remove_tail(char *path) +{ + int i; + + for (i = strlen(path) - 1; i > 0; --i) + if (path[i] == '/' || path[i] == '\\') + { + path[i] = NUL; + break; + } +} + + +char installdir[MAX_PATH-9]; // top of the installation dir, where the + // install.exe is located, E.g.: + // "c:\vim\vim60" +int runtimeidx; // index in installdir[] where "vim60" starts +char *sysdrive; // system drive or "c:\" + +/* + * Setup for using this program. + * Sets "installdir[]". + */ + static void +do_inits(char **argv) +{ + // Find out the full path of our executable. + if (my_fullpath(installdir, argv[0], sizeof(installdir)) == NULL) + { + printf("ERROR: Cannot get name of executable\n"); + myexit(1); + } + // remove the tail, the executable name "install.exe" + remove_tail(installdir); + + // change to the installdir + mch_chdir(installdir); + + // Find the system drive. Only used for searching the Vim executable, not + // very important. + sysdrive = getenv("SYSTEMDRIVE"); + if (sysdrive == NULL || *sysdrive == NUL) + sysdrive = "C:\\"; +} diff --git a/src/drawline.c b/src/drawline.c new file mode 100644 index 0000000..5c64750 --- /dev/null +++ b/src/drawline.c @@ -0,0 +1,4099 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * drawline.c: Functions for drawing window lines on the screen. + * This is the middle level, drawscreen.c is the higher level and screen.c the + * lower level. + */ + +#include "vim.h" + +#ifdef FEAT_SYN_HL +/* + * Advance **color_cols and return TRUE when there are columns to draw. + */ + static int +advance_color_col(int vcol, int **color_cols) +{ + while (**color_cols >= 0 && vcol > **color_cols) + ++*color_cols; + return (**color_cols >= 0); +} +#endif + +#ifdef FEAT_SYN_HL +/* + * Used when 'cursorlineopt' contains "screenline": compute the margins between + * which the highlighting is used. + */ + static void +margin_columns_win(win_T *wp, int *left_col, int *right_col) +{ + // cache previous calculations depending on w_virtcol + static int saved_w_virtcol; + static win_T *prev_wp; + static int prev_left_col; + static int prev_right_col; + static int prev_col_off; + + int cur_col_off = win_col_off(wp); + int width1; + int width2; + + if (saved_w_virtcol == wp->w_virtcol + && prev_wp == wp && prev_col_off == cur_col_off) + { + *right_col = prev_right_col; + *left_col = prev_left_col; + return; + } + + width1 = wp->w_width - cur_col_off; + width2 = width1 + win_col_off2(wp); + + *left_col = 0; + *right_col = width1; + + if (wp->w_virtcol >= (colnr_T)width1) + *right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2; + if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) + *left_col = (wp->w_virtcol - width1) / width2 * width2 + width1; + + // cache values + prev_left_col = *left_col; + prev_right_col = *right_col; + prev_wp = wp; + saved_w_virtcol = wp->w_virtcol; + prev_col_off = cur_col_off; +} +#endif + +#if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \ + || defined(FEAT_SYN_HL) || defined(FEAT_DIFF) +// using an attribute for the whole line +# define LINE_ATTR +#endif + +// structure with variables passed between win_line() and other functions +typedef struct { + int draw_state; // what to draw next + + linenr_T lnum; // line number to be drawn + + int startrow; // first row in the window to be drawn + int row; // row in the window, excl w_winrow + int screen_row; // row on the screen, incl w_winrow + + long vcol; // virtual column, before wrapping + int col; // visual column on screen, after wrapping +#ifdef FEAT_CONCEAL + int boguscols; // nonexistent columns added to "col" to force + // wrapping + int vcol_off_co; // offset for concealed characters +#endif + int vcol_off_tp; // offset for virtual text +#ifdef FEAT_SYN_HL + int draw_color_col; // highlight colorcolumn + int *color_cols; // pointer to according columns array +#endif + int eol_hl_off; // 1 if highlighted char after EOL + + unsigned off; // offset in ScreenLines/ScreenAttrs + + int win_attr; // background for the whole window, except + // margins and "~" lines. + int wcr_attr; // attributes from 'wincolor' +#ifdef FEAT_SYN_HL + int cul_attr; // set when 'cursorline' active +#endif +#ifdef LINE_ATTR + int line_attr; // for the whole line, includes 'cursorline' +#endif + + int screen_line_flags; // flags for screen_line() + + int fromcol; // start of inverting + int tocol; // end of inverting + +#ifdef FEAT_LINEBREAK + long vcol_sbr; // virtual column after showbreak + int need_showbreak; // overlong line, skipping first x chars + int dont_use_showbreak; // do not use 'showbreak' +#endif +#ifdef FEAT_PROP_POPUP + int text_prop_above_count; +#endif + + // TRUE when 'cursorlineopt' has "screenline" and cursor is in this line + int cul_screenline; + + int char_attr; // attributes for the next character + + int n_extra; // number of extra bytes + char_u *p_extra; // string of extra chars, plus NUL, only used + // when c_extra and c_final are NUL + char_u *p_extra_free; // p_extra buffer that needs to be freed + int extra_attr; // attributes for p_extra, should be combined + // with win_attr if needed + int n_attr_skip; // chars to skip before using extra_attr + int c_extra; // extra chars, all the same + int c_final; // final char, mandatory if set + int extra_for_textprop; // wlv.n_extra set for textprop + + // saved "extra" items for when draw_state becomes WL_LINE (again) + int saved_n_extra; + char_u *saved_p_extra; + int saved_extra_attr; + int saved_n_attr_skip; + int saved_extra_for_textprop; + int saved_c_extra; + int saved_c_final; + int saved_char_attr; + + char_u extra[NUMBUFLEN + MB_MAXBYTES]; + // "%ld " and 'fdc' must fit in here, as well + // any text sign + +#ifdef FEAT_DIFF + hlf_T diff_hlf; // type of diff highlighting +#endif + int filler_lines; // nr of filler lines to be drawn + int filler_todo; // nr of filler lines still to do + 1 +#ifdef FEAT_SIGNS + sign_attrs_T sattr; +#endif +} winlinevars_T; + +// draw_state values for items that are drawn in sequence: +#define WL_START 0 // nothing done yet, must be zero +#define WL_CMDLINE (WL_START + 1) // cmdline window column +#ifdef FEAT_FOLDING +# define WL_FOLD (WL_CMDLINE + 1) // 'foldcolumn' +#else +# define WL_FOLD WL_CMDLINE +#endif +#ifdef FEAT_SIGNS +# define WL_SIGN (WL_FOLD + 1) // column for signs +#else +# define WL_SIGN WL_FOLD // column for signs +#endif +#define WL_NR (WL_SIGN + 1) // line number +#ifdef FEAT_LINEBREAK +# define WL_BRI (WL_NR + 1) // 'breakindent' +#else +# define WL_BRI WL_NR +#endif +#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) +# define WL_SBR (WL_BRI + 1) // 'showbreak' or 'diff' +#else +# define WL_SBR WL_BRI +#endif +#define WL_LINE (WL_SBR + 1) // text in the line + +#if defined(FEAT_SIGNS) || defined(FEAT_FOLDING) +/* + * Return TRUE if CursorLineSign highlight is to be used. + */ + static int +use_cursor_line_highlight(win_T *wp, linenr_T lnum) +{ + return wp->w_p_cul + && lnum == wp->w_cursor.lnum + && (wp->w_p_culopt_flags & CULOPT_NBR); +} +#endif + + +#ifdef FEAT_FOLDING +/* + * Setup for drawing the 'foldcolumn', if there is one. + */ + static void +handle_foldcolumn(win_T *wp, winlinevars_T *wlv) +{ + int fdc = compute_foldcolumn(wp, 0); + + if (fdc <= 0) + return; + + // Allocate a buffer, "wlv->extra[]" may already be in use. + vim_free(wlv->p_extra_free); + wlv->p_extra_free = alloc(MAX_MCO * fdc + 1); + if (wlv->p_extra_free == NULL) + return; + + wlv->n_extra = (int)fill_foldcolumn(wlv->p_extra_free, + wp, FALSE, wlv->lnum); + wlv->p_extra_free[wlv->n_extra] = NUL; + wlv->p_extra = wlv->p_extra_free; + wlv->c_extra = NUL; + wlv->c_final = NUL; + if (use_cursor_line_highlight(wp, wlv->lnum)) + wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_CLF)); + else + wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_FC)); +} +#endif + +#ifdef FEAT_SIGNS +/* + * Get information needed to display the sign in line "wlv->lnum" in window + * "wp". + * If "nrcol" is TRUE, the sign is going to be displayed in the number column. + * Otherwise the sign is going to be displayed in the sign column. + */ + static void +get_sign_display_info( + int nrcol, + win_T *wp, + winlinevars_T *wlv) +{ + int text_sign; +# ifdef FEAT_SIGN_ICONS + int icon_sign; +# endif + + // Draw two cells with the sign value or blank. + wlv->c_extra = ' '; + wlv->c_final = NUL; + if (nrcol) + wlv->n_extra = number_width(wp) + 1; + else + { + if (use_cursor_line_highlight(wp, wlv->lnum)) + wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_CLS)); + else + wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_SC)); + wlv->n_extra = 2; + } + + if (wlv->row == wlv->startrow +#ifdef FEAT_DIFF + + wlv->filler_lines && wlv->filler_todo <= 0 +#endif + ) + { + text_sign = (wlv->sattr.sat_text != NULL) ? wlv->sattr.sat_typenr : 0; +# ifdef FEAT_SIGN_ICONS + icon_sign = (wlv->sattr.sat_icon != NULL) ? wlv->sattr.sat_typenr : 0; + if (gui.in_use && icon_sign != 0) + { + // Use the image in this position. + if (nrcol) + { + wlv->c_extra = NUL; + sprintf((char *)wlv->extra, "%-*c ", + number_width(wp), SIGN_BYTE); + wlv->p_extra = wlv->extra; + wlv->n_extra = (int)STRLEN(wlv->p_extra); + } + else + wlv->c_extra = SIGN_BYTE; +# ifdef FEAT_NETBEANS_INTG + if (netbeans_active() && (buf_signcount(wp->w_buffer, wlv->lnum) + > 1)) + { + if (nrcol) + { + wlv->c_extra = NUL; + sprintf((char *)wlv->extra, "%-*c ", number_width(wp), + MULTISIGN_BYTE); + wlv->p_extra = wlv->extra; + wlv->n_extra = (int)STRLEN(wlv->p_extra); + } + else + wlv->c_extra = MULTISIGN_BYTE; + } +# endif + wlv->c_final = NUL; + wlv->char_attr = icon_sign; + } + else +# endif + if (text_sign != 0) + { + wlv->p_extra = wlv->sattr.sat_text; + if (wlv->p_extra != NULL) + { + if (nrcol) + { + int width = number_width(wp) - 2; + int n; + + for (n = 0; n < width; n++) + wlv->extra[n] = ' '; + vim_snprintf((char *)wlv->extra + n, + sizeof(wlv->extra) - n, "%s ", wlv->p_extra); + wlv->p_extra = wlv->extra; + } + wlv->c_extra = NUL; + wlv->c_final = NUL; + wlv->n_extra = (int)STRLEN(wlv->p_extra); + } + + if (use_cursor_line_highlight(wp, wlv->lnum) + && wlv->sattr.sat_culhl > 0) + wlv->char_attr = wlv->sattr.sat_culhl; + else + wlv->char_attr = wlv->sattr.sat_texthl; + } + } +} +#endif + +/* + * Display the absolute or relative line number. After the first row fill with + * blanks when the 'n' flag isn't in 'cpo'. + */ + static void +handle_lnum_col( + win_T *wp, + winlinevars_T *wlv, + int sign_present UNUSED, + int num_attr UNUSED) +{ + int has_cpo_n = vim_strchr(p_cpo, CPO_NUMCOL) != NULL; + int lnum_row = wlv->startrow + wlv->filler_lines +#ifdef FEAT_PROP_POPUP + + wlv->text_prop_above_count +#endif + ; + + if ((wp->w_p_nu || wp->w_p_rnu) + && (wlv->row <= lnum_row || !has_cpo_n) + // there is no line number in a wrapped line when "n" is in + // 'cpoptions', but 'breakindent' assumes it anyway. + && !((has_cpo_n +#ifdef FEAT_LINEBREAK + && !wp->w_p_bri +#endif + ) && wp->w_skipcol > 0 && wlv->lnum == wp->w_topline)) + { +#ifdef FEAT_SIGNS + // If 'signcolumn' is set to 'number' and a sign is present + // in 'lnum', then display the sign instead of the line + // number. + if ((*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u') && sign_present) + get_sign_display_info(TRUE, wp, wlv); + else +#endif + { + // Draw the line number (empty space after wrapping). + // When there are text properties above the line put the line number + // below them. + if (wlv->row == lnum_row + && (wp->w_skipcol == 0 || wlv->row > wp->w_winrow + || (wp->w_p_nu && wp->w_p_rnu))) + { + long num; + char *fmt = "%*ld "; + + if (wp->w_p_nu && !wp->w_p_rnu) + // 'number' + 'norelativenumber' + num = (long)wlv->lnum; + else + { + // 'relativenumber', don't use negative numbers + num = labs((long)get_cursor_rel_lnum(wp, wlv->lnum)); + if (num == 0 && wp->w_p_nu && wp->w_p_rnu) + { + // 'number' + 'relativenumber' + num = wlv->lnum; + fmt = "%-*ld "; + } + } + + sprintf((char *)wlv->extra, fmt, number_width(wp), num); + if (wp->w_skipcol > 0 && wlv->startrow == 0) + for (wlv->p_extra = wlv->extra; *wlv->p_extra == ' '; + ++wlv->p_extra) + *wlv->p_extra = '-'; +#ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) // reverse line numbers + { + char_u *p1, *p2; + int t; + + // like rl_mirror(), but keep the space at the end + p2 = skipwhite(wlv->extra); + p2 = skiptowhite(p2) - 1; + for (p1 = skipwhite(wlv->extra); p1 < p2; ++p1, --p2) + { + t = *p1; + *p1 = *p2; + *p2 = t; + } + } +#endif + wlv->p_extra = wlv->extra; + wlv->c_extra = NUL; + wlv->c_final = NUL; + } + else + { + wlv->c_extra = ' '; + wlv->c_final = NUL; + } + wlv->n_extra = number_width(wp) + 1; + wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_N)); +#ifdef FEAT_SYN_HL + // When 'cursorline' is set highlight the line number of + // the current line differently. + // When 'cursorlineopt' does not have "line" only + // highlight the line number itself. + // TODO: Can we use CursorLine instead of CursorLineNr + // when CursorLineNr isn't set? + if (wp->w_p_cul + && wlv->lnum == wp->w_cursor.lnum + && (wp->w_p_culopt_flags & CULOPT_NBR) + && (wlv->row == wlv->startrow + wlv->filler_lines + || (wlv->row > wlv->startrow + wlv->filler_lines + && (wp->w_p_culopt_flags & CULOPT_LINE)))) + wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_CLN)); +#endif + if (wp->w_p_rnu && wlv->lnum < wp->w_cursor.lnum + && HL_ATTR(HLF_LNA) != 0) + // Use LineNrAbove + wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_LNA)); + if (wp->w_p_rnu && wlv->lnum > wp->w_cursor.lnum + && HL_ATTR(HLF_LNB) != 0) + // Use LineNrBelow + wlv->char_attr = hl_combine_attr(wlv->wcr_attr, HL_ATTR(HLF_LNB)); + } +#ifdef FEAT_SIGNS + if (num_attr) + wlv->char_attr = num_attr; +#endif + } +} + +#ifdef FEAT_LINEBREAK + static void +handle_breakindent(win_T *wp, winlinevars_T *wlv) +{ + if (wp->w_briopt_sbr && wlv->draw_state == WL_BRI - 1 + && *get_showbreak_value(wp) != NUL) + // draw indent after showbreak value + wlv->draw_state = WL_BRI; + else if (wp->w_briopt_sbr && wlv->draw_state == WL_SBR) + // After the showbreak, draw the breakindent + wlv->draw_state = WL_BRI - 1; + + // draw 'breakindent': indent wrapped text accordingly + if (wlv->draw_state == WL_BRI - 1) + { + wlv->draw_state = WL_BRI; + // if wlv->need_showbreak is set, breakindent also applies + if (wp->w_p_bri && (wlv->row != wlv->startrow || wlv->need_showbreak) +# ifdef FEAT_DIFF + && wlv->filler_lines == 0 +# endif +# ifdef FEAT_PROP_POPUP + && !wlv->dont_use_showbreak +# endif + ) + { + wlv->char_attr = 0; +# ifdef FEAT_DIFF + if (wlv->diff_hlf != (hlf_T)0) + wlv->char_attr = HL_ATTR(wlv->diff_hlf); +# endif + wlv->p_extra = NULL; + wlv->c_extra = ' '; + wlv->c_final = NUL; + wlv->n_extra = get_breakindent_win(wp, + ml_get_buf(wp->w_buffer, wlv->lnum, FALSE)); + if (wlv->row == wlv->startrow) + { + wlv->n_extra -= win_col_off2(wp); + if (wlv->n_extra < 0) + wlv->n_extra = 0; + } + if (wp->w_skipcol > 0 && wlv->startrow == 0 + && wp->w_p_wrap && wp->w_briopt_sbr) + wlv->need_showbreak = FALSE; + // Correct end of highlighted area for 'breakindent', + // required when 'linebreak' is also set. + if (wlv->tocol == wlv->vcol) + wlv->tocol += wlv->n_extra; + } + } +} +#endif + +#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) + static void +handle_showbreak_and_filler(win_T *wp, winlinevars_T *wlv) +{ +# ifdef FEAT_DIFF + if (wlv->filler_todo > 0) + { + // Draw "deleted" diff line(s). + if (char2cells(wp->w_fill_chars.diff) > 1) + { + wlv->c_extra = '-'; + wlv->c_final = NUL; + } + else + { + wlv->c_extra = wp->w_fill_chars.diff; + wlv->c_final = NUL; + } +# ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + wlv->n_extra = wlv->col + 1; + else +# endif + wlv->n_extra = wp->w_width - wlv->col; + wlv->char_attr = HL_ATTR(HLF_DED); + } +# endif + +# ifdef FEAT_LINEBREAK + char_u *sbr = get_showbreak_value(wp); + if (*sbr != NUL && wlv->need_showbreak) + { + // Draw 'showbreak' at the start of each broken line. + wlv->p_extra = sbr; + wlv->c_extra = NUL; + wlv->c_final = NUL; + wlv->n_extra = (int)STRLEN(sbr); + if (wp->w_skipcol == 0 || wlv->startrow != 0 || !wp->w_p_wrap) + wlv->need_showbreak = FALSE; + wlv->vcol_sbr = wlv->vcol + MB_CHARLEN(sbr); + // Correct end of highlighted area for 'showbreak', + // required when 'linebreak' is also set. + if (wlv->tocol == wlv->vcol) + wlv->tocol += wlv->n_extra; + // combine 'showbreak' with 'wincolor' + wlv->char_attr = hl_combine_attr(wlv->win_attr, HL_ATTR(HLF_AT)); +# ifdef FEAT_SYN_HL + // combine 'showbreak' with 'cursorline' + if (wlv->cul_attr != 0) + wlv->char_attr = hl_combine_attr(wlv->char_attr, wlv->cul_attr); +# endif + } +# endif +} +#endif + +#if defined(FEAT_PROP_POPUP) || defined(PROTO) +/* + * Return the cell size of virtual text after truncation. + */ + static int +textprop_size_after_trunc( + win_T *wp, + int flags, // TP_FLAG_ALIGN_* + int added, + int padding, + char_u *text, + int *n_used_ptr) +{ + int space = (flags & (TP_FLAG_ALIGN_BELOW | TP_FLAG_ALIGN_ABOVE)) + ? wp->w_width - win_col_off(wp) : added; + int len = (int)STRLEN(text); + int strsize = 0; + int n_used; + + // if the remaining size is to small and 'wrap' is set we wrap anyway and + // use the next line + if (space < PROP_TEXT_MIN_CELLS && wp->w_p_wrap) + space += wp->w_width; + if (flags & (TP_FLAG_ALIGN_BELOW | TP_FLAG_ALIGN_ABOVE)) + space -= padding; + for (n_used = 0; n_used < len; n_used += (*mb_ptr2len)(text + n_used)) + { + int clen = ptr2cells(text + n_used); + + if (strsize + clen > space) + break; + strsize += clen; + } + *n_used_ptr = n_used; + return strsize; +} + +/* + * Take care of padding, right-align and truncation of virtual text after a + * line. + * if "n_attr" is not NULL then "n_extra" and "p_extra" are adjusted for any + * padding, right-align and truncation. Otherwise only the size is computed. + * When "n_attr" is NULL returns the number of screen cells used. + * Otherwise returns TRUE when drawing continues on the next line. + */ + int +text_prop_position( + win_T *wp, + textprop_T *tp, + int vcol, // current text column + int scr_col, // current screen column + int *n_extra, // nr of bytes for virtual text + char_u **p_extra, // virtual text + int *n_attr, // attribute cells, NULL if not used + int *n_attr_skip, // cells to skip attr, NULL if not used + int do_skip) // skip_cells is not zero +{ + int right = (tp->tp_flags & TP_FLAG_ALIGN_RIGHT); + int above = (tp->tp_flags & TP_FLAG_ALIGN_ABOVE); + int below = (tp->tp_flags & TP_FLAG_ALIGN_BELOW); + int wrap = tp->tp_col < MAXCOL || (tp->tp_flags & TP_FLAG_WRAP); + int padding = tp->tp_col == MAXCOL && tp->tp_len > 1 + ? tp->tp_len - 1 : 0; + int col_with_padding = scr_col + (below ? 0 : padding); + int room = wp->w_width - col_with_padding; + int before = room; // spaces before the text + int after = 0; // spaces after the text + int n_used = *n_extra; + char_u *l = NULL; + int strsize = vim_strsize(*p_extra); + int cells = wrap ? strsize : textprop_size_after_trunc(wp, + tp->tp_flags, before, padding, *p_extra, &n_used); + + if (wrap || right || above || below || padding > 0 || n_used < *n_extra) + { + int col_off = win_col_off(wp) - win_col_off2(wp); + + if (above) + { + before = 0; + after = wp->w_width - cells - win_col_off(wp) - padding; + } + else + { + // Right-align: fill with before + if (right) + before -= cells; + + // Below-align: empty line add one character + if (below && vcol == 0 && col_with_padding == col_off + && wp->w_width - col_off == before) + col_with_padding += 1; + + if (before < 0 + || !(right || below) + || (below ? (col_with_padding <= col_off || !wp->w_p_wrap) + : (n_used < *n_extra))) + { + if (right && (wrap + || (room < PROP_TEXT_MIN_CELLS && wp->w_p_wrap))) + { + // right-align on next line instead of wrapping if possible + before = wp->w_width - col_off - strsize + room; + if (before < 0) + before = 0; + else + n_used = *n_extra; + } + else if (below && before > vcol && do_skip) + before -= vcol; + else + before = 0; + } + } + + // With 'nowrap' add one to show the "extends" character if needed (it + // doesn't show if the text just fits). + if (!wp->w_p_wrap + && n_used < *n_extra + && wp->w_lcs_chars.ext != NUL + && wp->w_p_list) + ++n_used; + + // add 1 for NUL, 2 for when '…' is used + if (n_attr != NULL) + l = alloc(n_used + before + after + padding + 3); + if (n_attr == NULL || l != NULL) + { + int off = 0; + + if (n_attr != NULL) + { + vim_memset(l, ' ', before); + off += before; + if (padding > 0) + { + vim_memset(l + off, ' ', padding); + off += padding; + } + vim_strncpy(l + off, *p_extra, n_used); + off += n_used; + } + else + { + off = before + after + padding + n_used; + cells += before + after + padding; + } + if (n_attr != NULL) + { + if (n_used < *n_extra && wp->w_p_wrap) + { + char_u *lp = l + off - 1; + + if (has_mbyte) + { + // change last character to '…' + lp -= (*mb_head_off)(l, lp); + STRCPY(lp, "…"); + n_used = lp - l + 3 - before - padding; + } + else + // change last character to '>' + *lp = '>'; + } + else if (after > 0) + { + vim_memset(l + off, ' ', after); + l[off + after] = NUL; + } + + *p_extra = l; + *n_extra = n_used + before + after + padding; + *n_attr = mb_charlen(*p_extra); + if (above) + *n_attr -= padding + after; + + // n_attr_skip will not be decremented before draw_state is + // WL_LINE + *n_attr_skip = before + padding; + } + } + } + + if (n_attr == NULL) + return cells; + return (below && col_with_padding > win_col_off(wp) && !wp->w_p_wrap); +} +#endif + +/* + * Call screen_line() using values from "wlv". + * Also takes care of putting "<<<" on the first line for 'smoothscroll' + * when 'showbreak' is not set. + */ + static void +wlv_screen_line(win_T *wp, winlinevars_T *wlv, int negative_width) +{ + if (wlv->row == 0 && wp->w_skipcol > 0 +#if defined(FEAT_LINEBREAK) + // do not overwrite the 'showbreak' text with "<<<" + && *get_showbreak_value(wp) == NUL +#endif + // do not overwrite the 'listchars' "precedes" text with "<<<" + && !(wp->w_p_list && wp->w_lcs_chars.prec != 0)) + { + int off = (int)(current_ScreenLine - ScreenLines); + int skip = 0; + + if (wp->w_p_nu && wp->w_p_rnu) + // Do not overwrite the line number, change "123 text" to + // "123>>>xt". + while (skip < wp->w_width && VIM_ISDIGIT(ScreenLines[off])) + { + ++off; + ++skip; + } + + for (int i = 0; i < 3 && i + skip < wp->w_width; ++i) + { + ScreenLines[off] = '<'; + if (enc_utf8) + ScreenLinesUC[off] = 0; + ScreenAttrs[off] = HL_ATTR(HLF_AT); + ++off; + } + } + + screen_line(wp, wlv->screen_row, wp->w_wincol, wlv->col, + negative_width ? -wp->w_width : wp->w_width, + wlv->screen_line_flags); +} + +/* + * Called when finished with the line: draw the screen line and handle any + * highlighting until the right of the window. + */ + static void +draw_screen_line(win_T *wp, winlinevars_T *wlv) +{ +#ifdef FEAT_SYN_HL + long v; + + // Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. + if (wp->w_p_wrap) + v = wlv->startrow == 0 ? wp->w_skipcol : 0; + else + v = wp->w_leftcol; + + // check if line ends before left margin + if (wlv->vcol < v + wlv->col - win_col_off(wp)) + wlv->vcol = v + wlv->col - win_col_off(wp); +# ifdef FEAT_CONCEAL + // Get rid of the boguscols now, we want to draw until the right + // edge for 'cursorcolumn'. + wlv->col -= wlv->boguscols; + wlv->boguscols = 0; +# define VCOL_HLC (wlv->vcol - wlv->vcol_off_co - wlv->vcol_off_tp) +# else +# define VCOL_HLC (wlv->vcol - wlv->vcol_off_tp) +# endif + + if (wlv->draw_color_col) + wlv->draw_color_col = advance_color_col(VCOL_HLC, &wlv->color_cols); + + if (((wp->w_p_cuc + && (int)wp->w_virtcol >= VCOL_HLC - wlv->eol_hl_off + && (int)wp->w_virtcol < + (long)wp->w_width * (wlv->row - wlv->startrow + 1) + v + && wlv->lnum != wp->w_cursor.lnum) + || wlv->draw_color_col +# ifdef LINE_ATTR + || wlv->line_attr != 0 +# endif + || wlv->win_attr != 0) +# ifdef FEAT_RIGHTLEFT + && !wp->w_p_rl +# endif + ) + { + int rightmost_vcol = 0; + int i; + + if (wp->w_p_cuc) + rightmost_vcol = wp->w_virtcol; + if (wlv->draw_color_col) + // determine rightmost colorcolumn to possibly draw + for (i = 0; wlv->color_cols[i] >= 0; ++i) + if (rightmost_vcol < wlv->color_cols[i]) + rightmost_vcol = wlv->color_cols[i]; + + while (wlv->col < wp->w_width) + { + ScreenLines[wlv->off] = ' '; + if (enc_utf8) + ScreenLinesUC[wlv->off] = 0; + ScreenCols[wlv->off] = MAXCOL; + ++wlv->col; + if (wlv->draw_color_col) + wlv->draw_color_col = advance_color_col( + VCOL_HLC, &wlv->color_cols); + + int attr = wlv->win_attr; + if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) + attr = HL_ATTR(HLF_CUC); + else if (wlv->draw_color_col && VCOL_HLC == *wlv->color_cols) + attr = HL_ATTR(HLF_MC); +# ifdef LINE_ATTR + else if (wlv->line_attr != 0) + attr = wlv->line_attr; +# endif + ScreenAttrs[wlv->off++] = attr; + + if (VCOL_HLC >= rightmost_vcol +# ifdef LINE_ATTR + && wlv->line_attr == 0 +# endif + && wlv->win_attr == 0) + break; + + ++wlv->vcol; + } + } +#endif + + wlv_screen_line(wp, wlv, FALSE); + ++wlv->row; + ++wlv->screen_row; +} +#undef VCOL_HLC + +/* + * Start a screen line at column zero. + * When "save_extra" is TRUE save and reset n_extra, p_extra, etc. + */ + static void +win_line_start(win_T *wp UNUSED, winlinevars_T *wlv, int save_extra) +{ + wlv->col = 0; + wlv->off = (unsigned)(current_ScreenLine - ScreenLines); + +#ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + { + // Rightleft window: process the text in the normal direction, but put + // it in current_ScreenLine[] from right to left. Start at the + // rightmost column of the window. + wlv->col = wp->w_width - 1; + wlv->off += wlv->col; + wlv->screen_line_flags |= SLF_RIGHTLEFT; + } +#endif + if (save_extra) + { + // reset the drawing state for the start of a wrapped line + wlv->draw_state = WL_START; + wlv->saved_n_extra = wlv->n_extra; + wlv->saved_p_extra = wlv->p_extra; + wlv->saved_extra_attr = wlv->extra_attr; + wlv->saved_n_attr_skip = wlv->n_attr_skip; + wlv->saved_extra_for_textprop = wlv->extra_for_textprop; + wlv->saved_c_extra = wlv->c_extra; + wlv->saved_c_final = wlv->c_final; +#ifdef FEAT_SYN_HL + if (!(wlv->cul_screenline +# ifdef FEAT_DIFF + && wlv->diff_hlf == (hlf_T)0 +# endif + )) + wlv->saved_char_attr = wlv->char_attr; + else +#endif + wlv->saved_char_attr = 0; + + // these are not used until restored in win_line_continue() + wlv->n_extra = 0; + wlv->n_attr_skip = 0; + } +} + +/* + * Called when wlv->draw_state is set to WL_LINE. + */ + static void +win_line_continue(winlinevars_T *wlv) +{ + if (wlv->saved_n_extra > 0) + { + // Continue item from end of wrapped line. + wlv->n_extra = wlv->saved_n_extra; + wlv->saved_n_extra = 0; + wlv->c_extra = wlv->saved_c_extra; + wlv->c_final = wlv->saved_c_final; + wlv->p_extra = wlv->saved_p_extra; + wlv->extra_attr = wlv->saved_extra_attr; + wlv->n_attr_skip = wlv->saved_n_attr_skip; + wlv->extra_for_textprop = wlv->saved_extra_for_textprop; + wlv->char_attr = wlv->saved_char_attr; + } + else + wlv->char_attr = wlv->win_attr; +} + +#ifdef FEAT_SYN_HL + static void +apply_cursorline_highlight( + winlinevars_T *wlv, + int sign_present UNUSED) +{ + wlv->cul_attr = HL_ATTR(HLF_CUL); +# ifdef FEAT_SIGNS + // Combine the 'cursorline' and sign highlighting, depending on + // the sign priority. + if (sign_present && wlv->sattr.sat_linehl > 0) + { + if (wlv->sattr.sat_priority >= 100) + wlv->line_attr = hl_combine_attr(wlv->cul_attr, wlv->line_attr); + else + wlv->line_attr = hl_combine_attr(wlv->line_attr, wlv->cul_attr); + } + else +# endif +# if defined(FEAT_QUICKFIX) + // let the line attribute overrule 'cursorline', otherwise + // it disappears when both have background set; + // 'cursorline' can use underline or bold to make it show + wlv->line_attr = hl_combine_attr(wlv->cul_attr, wlv->line_attr); +# else + wlv->line_attr = wlv->cul_attr; +# endif +} +#endif + +/* + * Display line "lnum" of window 'wp' on the screen. + * Start at row "startrow", stop when "endrow" is reached. + * wp->w_virtcol needs to be valid. + * + * Return the number of last row the line occupies. + */ + int +win_line( + win_T *wp, + linenr_T lnum, + int startrow, + int endrow, + int nochange UNUSED, // not updating for changed text + int number_only) // only update the number column +{ + winlinevars_T wlv; // variables passed between functions + + int c = 0; // init for GCC + long vcol_prev = -1; // "wlv.vcol" of previous character + char_u *line; // current line + char_u *ptr; // current position in "line" + +#ifdef FEAT_PROP_POPUP + char_u *p_extra_free2 = NULL; // another p_extra to be freed +#endif +#if defined(FEAT_LINEBREAK) && defined(FEAT_PROP_POPUP) + int in_linebreak = FALSE; // n_extra set for showing linebreak +#endif + static char_u *at_end_str = (char_u *)""; // used for p_extra when + // displaying eol at end-of-line + int lcs_eol_one = wp->w_lcs_chars.eol; // eol until it's been used + int lcs_prec_todo = wp->w_lcs_chars.prec; + // prec until it's been used + + int n_attr = 0; // chars with special attr + int saved_attr2 = 0; // char_attr saved for n_attr + int n_attr3 = 0; // chars with overruling special attr + int saved_attr3 = 0; // char_attr saved for n_attr3 + + int n_skip = 0; // nr of cells to skip for 'nowrap' or + // concealing +#ifdef FEAT_PROP_POPUP + int skip_cells = 0; // nr of cells to skip for virtual text + // after the line, when w_skipcol is + // larger than the text length +#endif + + int fromcol_prev = -2; // start of inverting after cursor + int noinvcur = FALSE; // don't invert the cursor + int lnum_in_visual_area = FALSE; + pos_T pos; + long v; + + int attr_pri = FALSE; // char_attr has priority + int area_highlighting = FALSE; // Visual or incsearch highlighting + // in this line + int vi_attr = 0; // attributes for Visual and incsearch + // highlighting + int area_attr = 0; // attributes desired by highlighting + int search_attr = 0; // attributes desired by 'hlsearch' +#ifdef FEAT_SYN_HL + int vcol_save_attr = 0; // saved attr for 'cursorcolumn' + int syntax_attr = 0; // attributes desired by syntax + int prev_syntax_col = -1; // column of prev_syntax_attr + int prev_syntax_attr = 0; // syntax_attr at prev_syntax_col + int has_syntax = FALSE; // this buffer has syntax highl. + int save_did_emsg; +#endif +#ifdef FEAT_PROP_POPUP + int did_line = FALSE; // set to TRUE when line text done + int text_prop_count; + int text_prop_next = 0; // next text property to use + textprop_T *text_props = NULL; + int *text_prop_idxs = NULL; + int text_props_active = 0; + proptype_T *text_prop_type = NULL; + int text_prop_attr = 0; + int text_prop_attr_comb = 0; // text_prop_attr combined with + // syntax_attr + int text_prop_id = 0; // active property ID + int text_prop_flags = 0; + int text_prop_above = FALSE; // first doing virtual text above + int text_prop_follows = FALSE; // another text prop to display + int saved_search_attr = 0; // search_attr to be used when n_extra + // goes to zero + int saved_area_attr = 0; // idem for area_attr + int reset_extra_attr = FALSE; +#endif +#ifdef FEAT_SPELL + int has_spell = FALSE; // this buffer has spell checking + int can_spell = FALSE; +# define SPWORDLEN 150 + char_u nextline[SPWORDLEN * 2];// text with start of the next line + int nextlinecol = 0; // column where nextline[] starts + int nextline_idx = 0; // index in nextline[] where next line + // starts + int spell_attr = 0; // attributes desired by spelling + int word_end = 0; // last byte with same spell_attr + static linenr_T checked_lnum = 0; // line number for "checked_col" + static int checked_col = 0; // column in "checked_lnum" up to which + // there are no spell errors + static int cap_col = -1; // column to check for Cap word + static linenr_T capcol_lnum = 0; // line number where "cap_col" used + int cur_checked_col = 0; // checked column for current line +#endif + int extra_check = 0; // has extra highlighting + int multi_attr = 0; // attributes desired by multibyte + int mb_l = 1; // multi-byte byte length + int mb_c = 0; // decoded multi-byte character + int mb_utf8 = FALSE; // screen char is UTF-8 char + int u8cc[MAX_MCO]; // composing UTF-8 chars +#ifdef FEAT_DIFF + int change_start = MAXCOL; // first col of changed area + int change_end = -1; // last col of changed area +#endif + colnr_T trailcol = MAXCOL; // start of trailing spaces + colnr_T leadcol = 0; // start of leading spaces + int in_multispace = FALSE; // in multiple consecutive spaces + int multispace_pos = 0; // position in lcs-multispace string +#ifdef LINE_ATTR + int line_attr_save = 0; +#endif + int sign_present = FALSE; + int num_attr = 0; // attribute for the number column +#ifdef FEAT_ARABIC + int prev_c = 0; // previous Arabic character + int prev_c1 = 0; // first composing char for prev_c +#endif +#if defined(LINE_ATTR) + int did_line_attr = 0; +#endif +#ifdef FEAT_TERMINAL + int get_term_attr = FALSE; +#endif + +#if defined(FEAT_SYN_HL) || defined(FEAT_DIFF) + // margin columns for the screen line, needed for when 'cursorlineopt' + // contains "screenline" + int left_curline_col = 0; + int right_curline_col = 0; +#endif + +#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) + int feedback_col = 0; + int feedback_old_attr = -1; +#endif + +#if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA) + int match_conc = 0; // cchar for match functions +#endif +#if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA) || defined(FEAT_LINEBREAK) + int on_last_col = FALSE; +#endif +#ifdef FEAT_CONCEAL + int syntax_flags = 0; + int syntax_seqnr = 0; + int prev_syntax_id = 0; + int conceal_attr = HL_ATTR(HLF_CONCEAL); + int is_concealing = FALSE; + int did_wcol = FALSE; + int old_boguscols = 0; +# define VCOL_HLC (wlv.vcol - wlv.vcol_off_co - wlv.vcol_off_tp) +# define FIX_FOR_BOGUSCOLS \ + { \ + wlv.n_extra += wlv.vcol_off_co; \ + wlv.vcol -= wlv.vcol_off_co; \ + wlv.vcol_off_co = 0; \ + wlv.col -= wlv.boguscols; \ + old_boguscols = wlv.boguscols; \ + wlv.boguscols = 0; \ + } +#else +# define VCOL_HLC (wlv.vcol - wlv.vcol_off_tp) +#endif + + if (startrow > endrow) // past the end already! + return startrow; + + CLEAR_FIELD(wlv); + + wlv.lnum = lnum; + wlv.startrow = startrow; + wlv.row = startrow; + wlv.screen_row = wlv.row + W_WINROW(wp); + wlv.fromcol = -10; + wlv.tocol = MAXCOL; +#ifdef FEAT_LINEBREAK + wlv.vcol_sbr = -1; +#endif + + if (!number_only) + { + // To speed up the loop below, set extra_check when there is linebreak, + // trailing white space and/or syntax processing to be done. +#ifdef FEAT_LINEBREAK + extra_check = wp->w_p_lbr; +#endif +#ifdef FEAT_SYN_HL + if (syntax_present(wp) && !wp->w_s->b_syn_error +# ifdef SYN_TIME_LIMIT + && !wp->w_s->b_syn_slow +# endif + ) + { + // Prepare for syntax highlighting in this line. When there is an + // error, stop syntax highlighting. + save_did_emsg = did_emsg; + did_emsg = FALSE; + syntax_start(wp, lnum); + if (did_emsg) + wp->w_s->b_syn_error = TRUE; + else + { + did_emsg = save_did_emsg; +#ifdef SYN_TIME_LIMIT + if (!wp->w_s->b_syn_slow) +#endif + { + has_syntax = TRUE; + extra_check = TRUE; + } + } + } + + // Check for columns to display for 'colorcolumn'. + wlv.color_cols = wp->w_p_cc_cols; + if (wlv.color_cols != NULL) + wlv.draw_color_col = advance_color_col(VCOL_HLC, &wlv.color_cols); +#endif + +#ifdef FEAT_TERMINAL + if (term_show_buffer(wp->w_buffer)) + { + extra_check = TRUE; + get_term_attr = TRUE; + wlv.win_attr = term_get_attr(wp, lnum, -1); + } +#endif + +#ifdef FEAT_SPELL + if (spell_check_window(wp)) + { + // Prepare for spell checking. + has_spell = TRUE; + extra_check = TRUE; + + // Get the start of the next line, so that words that wrap to the + // next line are found too: "etal.". + // Trick: skip a few chars for C/shell/Vim comments + nextline[SPWORDLEN] = NUL; + if (lnum < wp->w_buffer->b_ml.ml_line_count) + { + line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE); + spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN); + } + + // When a word wrapped from the previous line the start of the + // current line is valid. + if (lnum == checked_lnum) + cur_checked_col = checked_col; + checked_lnum = 0; + + // When there was a sentence end in the previous line may require a + // word starting with capital in this line. In line 1 always check + // the first word. + if (lnum != capcol_lnum) + cap_col = -1; + if (lnum == 1) + cap_col = 0; + capcol_lnum = 0; + } +#endif + + // handle Visual active in this window + if (VIsual_active && wp->w_buffer == curwin->w_buffer) + { + pos_T *top, *bot; + + if (LTOREQ_POS(curwin->w_cursor, VIsual)) + { + // Visual is after curwin->w_cursor + top = &curwin->w_cursor; + bot = &VIsual; + } + else + { + // Visual is before curwin->w_cursor + top = &VIsual; + bot = &curwin->w_cursor; + } + lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum); + if (VIsual_mode == Ctrl_V) + { + // block mode + if (lnum_in_visual_area) + { + wlv.fromcol = wp->w_old_cursor_fcol; + wlv.tocol = wp->w_old_cursor_lcol; + } + } + else + { + // non-block mode + if (lnum > top->lnum && lnum <= bot->lnum) + wlv.fromcol = 0; + else if (lnum == top->lnum) + { + if (VIsual_mode == 'V') // linewise + wlv.fromcol = 0; + else + { + getvvcol(wp, top, (colnr_T *)&wlv.fromcol, NULL, NULL); + if (gchar_pos(top) == NUL) + wlv.tocol = wlv.fromcol + 1; + } + } + if (VIsual_mode != 'V' && lnum == bot->lnum) + { + if (*p_sel == 'e' && bot->col == 0 && bot->coladd == 0) + { + wlv.fromcol = -10; + wlv.tocol = MAXCOL; + } + else if (bot->col == MAXCOL) + wlv.tocol = MAXCOL; + else + { + pos = *bot; + if (*p_sel == 'e') + getvvcol(wp, &pos, (colnr_T *)&wlv.tocol, + NULL, NULL); + else + { + getvvcol(wp, &pos, NULL, NULL, + (colnr_T *)&wlv.tocol); + ++wlv.tocol; + } + } + } + } + + // Check if the character under the cursor should not be inverted + if (!highlight_match && lnum == curwin->w_cursor.lnum + && wp == curwin +#ifdef FEAT_GUI + && !gui.in_use +#endif + ) + noinvcur = TRUE; + + // if inverting in this line set area_highlighting + if (wlv.fromcol >= 0) + { + area_highlighting = TRUE; + vi_attr = HL_ATTR(HLF_V); +#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) + if ((clip_star.available && !clip_star.owned + && clip_isautosel_star()) + || (clip_plus.available && !clip_plus.owned + && clip_isautosel_plus())) + vi_attr = HL_ATTR(HLF_VNC); +#endif + } + } + + // handle 'incsearch' and ":s///c" highlighting + else if (highlight_match + && wp == curwin + && lnum >= curwin->w_cursor.lnum + && lnum <= curwin->w_cursor.lnum + search_match_lines) + { + if (lnum == curwin->w_cursor.lnum) + getvcol(curwin, &(curwin->w_cursor), + (colnr_T *)&wlv.fromcol, NULL, NULL); + else + wlv.fromcol = 0; + if (lnum == curwin->w_cursor.lnum + search_match_lines) + { + pos.lnum = lnum; + pos.col = search_match_endcol; + getvcol(curwin, &pos, (colnr_T *)&wlv.tocol, NULL, NULL); + } + else + wlv.tocol = MAXCOL; + // do at least one character; happens when past end of line + if (wlv.fromcol == wlv.tocol && search_match_endcol) + wlv.tocol = wlv.fromcol + 1; + area_highlighting = TRUE; + vi_attr = HL_ATTR(HLF_I); + } + } + +#ifdef FEAT_DIFF + wlv.filler_lines = diff_check(wp, lnum); + if (wlv.filler_lines < 0) + { + if (wlv.filler_lines == -1) + { + if (diff_find_change(wp, lnum, &change_start, &change_end)) + wlv.diff_hlf = HLF_ADD; // added line + else if (change_start == 0) + wlv.diff_hlf = HLF_TXD; // changed text + else + wlv.diff_hlf = HLF_CHD; // changed line + } + else + wlv.diff_hlf = HLF_ADD; // added line + wlv.filler_lines = 0; + area_highlighting = TRUE; + } + if (lnum == wp->w_topline) + wlv.filler_lines = wp->w_topfill; + wlv.filler_todo = wlv.filler_lines; +#endif + +#ifdef FEAT_SIGNS + sign_present = buf_get_signattrs(wp, lnum, &wlv.sattr); + if (sign_present) + num_attr = wlv.sattr.sat_numhl; +#endif + +#ifdef LINE_ATTR +# ifdef FEAT_SIGNS + // If this line has a sign with line highlighting set wlv.line_attr. + if (sign_present) + wlv.line_attr = wlv.sattr.sat_linehl; +# endif +# if defined(FEAT_QUICKFIX) + // Highlight the current line in the quickfix window. + if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) + wlv.line_attr = HL_ATTR(HLF_QFL); +# endif + if (wlv.line_attr != 0) + area_highlighting = TRUE; +#endif + + line = ml_get_buf(wp->w_buffer, lnum, FALSE); + ptr = line; + +#ifdef FEAT_SPELL + if (has_spell && !number_only) + { + // For checking first word with a capital skip white space. + if (cap_col == 0) + cap_col = getwhitecols(line); + + // To be able to spell-check over line boundaries copy the end of the + // current line into nextline[]. Above the start of the next line was + // copied to nextline[SPWORDLEN]. + if (nextline[SPWORDLEN] == NUL) + { + // No next line or it is empty. + nextlinecol = MAXCOL; + nextline_idx = 0; + } + else + { + v = (long)STRLEN(line); + if (v < SPWORDLEN) + { + // Short line, use it completely and append the start of the + // next line. + nextlinecol = 0; + mch_memmove(nextline, line, (size_t)v); + STRMOVE(nextline + v, nextline + SPWORDLEN); + nextline_idx = v + 1; + } + else + { + // Long line, use only the last SPWORDLEN bytes. + nextlinecol = v - SPWORDLEN; + mch_memmove(nextline, line + nextlinecol, SPWORDLEN); + nextline_idx = SPWORDLEN + 1; + } + } + } +#endif + + if (wp->w_p_list) + { + if (wp->w_lcs_chars.space + || wp->w_lcs_chars.multispace != NULL + || wp->w_lcs_chars.leadmultispace != NULL + || wp->w_lcs_chars.trail + || wp->w_lcs_chars.lead + || wp->w_lcs_chars.nbsp) + extra_check = TRUE; + + // find start of trailing whitespace + if (wp->w_lcs_chars.trail) + { + trailcol = (colnr_T)STRLEN(ptr); + while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1])) + --trailcol; + trailcol += (colnr_T)(ptr - line); + } + // find end of leading whitespace + if (wp->w_lcs_chars.lead || wp->w_lcs_chars.leadmultispace != NULL) + { + leadcol = 0; + while (VIM_ISWHITE(ptr[leadcol])) + ++leadcol; + if (ptr[leadcol] == NUL) + // in a line full of spaces all of them are treated as trailing + leadcol = (colnr_T)0; + else + // keep track of the first column not filled with spaces + leadcol += (colnr_T)(ptr - line) + 1; + } + } + + wlv.wcr_attr = get_wcr_attr(wp); + if (wlv.wcr_attr != 0) + { + wlv.win_attr = wlv.wcr_attr; + area_highlighting = TRUE; + } + + // When w_skipcol is non-zero and there is virtual text above the actual + // text, then this much of the virtual text is skipped. + int skipcol_in_text_prop_above = 0; + +#ifdef FEAT_PROP_POPUP + if (WIN_IS_POPUP(wp)) + wlv.screen_line_flags |= SLF_POPUP; + + char_u *prop_start; + text_prop_count = get_text_props(wp->w_buffer, lnum, &prop_start, FALSE); + if (text_prop_count > 0) + { + // Make a copy of the properties, so that they are properly + // aligned. + text_props = ALLOC_MULT(textprop_T, text_prop_count); + if (text_props != NULL) + mch_memmove(text_props, prop_start, + text_prop_count * sizeof(textprop_T)); + + // Allocate an array for the indexes. + text_prop_idxs = ALLOC_MULT(int, text_prop_count); + if (text_prop_idxs == NULL) + VIM_CLEAR(text_props); + + if (text_props != NULL) + { + area_highlighting = TRUE; + extra_check = TRUE; + + // When skipping virtual text the props need to be sorted. The + // order is reversed! + if (lnum == wp->w_topline && wp->w_skipcol > 0) + { + for (int i = 0; i < text_prop_count; ++i) + text_prop_idxs[i] = i; + sort_text_props(wp->w_buffer, text_props, + text_prop_idxs, text_prop_count); + } + + // Text props "above" move the line number down to where the text + // is. Only count the ones that are visible, not those that are + // skipped because of w_skipcol. + int text_width = wp->w_width - win_col_off(wp); + for (int i = text_prop_count - 1; i >= 0; --i) + if (text_props[i].tp_flags & TP_FLAG_ALIGN_ABOVE) + { + if (lnum == wp->w_topline + && wp->w_skipcol - skipcol_in_text_prop_above + >= text_width) + { + // This virtual text above is skipped, remove it from + // the array. + skipcol_in_text_prop_above += text_width; + for (int j = i + 1; j < text_prop_count; ++j) + text_props[j - 1] = text_props[j]; + ++i; + --text_prop_count; + } + else + ++wlv.text_prop_above_count; + } + } + } + + if (number_only) + { + // skip over rows only used for virtual text above + wlv.row += wlv.text_prop_above_count; + if (wlv.row > endrow) + return wlv.row; + wlv.screen_row += wlv.text_prop_above_count; + } +#endif + + // 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the + // first character to be displayed. + if (wp->w_p_wrap) + v = startrow == 0 ? wp->w_skipcol - skipcol_in_text_prop_above : 0; + else + v = wp->w_leftcol; + if (v > 0 && !number_only) + { + char_u *prev_ptr = ptr; + chartabsize_T cts; + int charsize = 0; + + init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, ptr); + while (cts.cts_vcol < v && *cts.cts_ptr != NUL) + { + charsize = win_lbr_chartabsize(&cts, NULL); + cts.cts_vcol += charsize; + prev_ptr = cts.cts_ptr; + MB_PTR_ADV(cts.cts_ptr); + } + wlv.vcol = cts.cts_vcol; + ptr = cts.cts_ptr; + clear_chartabsize_arg(&cts); + + // When: + // - 'cuc' is set, or + // - 'colorcolumn' is set, or + // - 'virtualedit' is set, or + // - the visual mode is active, + // the end of the line may be before the start of the displayed part. + if (wlv.vcol < v && ( +#ifdef FEAT_SYN_HL + wp->w_p_cuc || wlv.draw_color_col || +#endif + virtual_active() || + (VIsual_active && wp->w_buffer == curwin->w_buffer))) + wlv.vcol = v; + + // Handle a character that's not completely on the screen: Put ptr at + // that character but skip the first few screen characters. + if (wlv.vcol > v) + { + wlv.vcol -= charsize; + ptr = prev_ptr; + // If the character fits on the screen, don't need to skip it. + // Except for a TAB. + if (((*mb_ptr2cells)(ptr) >= charsize || *ptr == TAB) + && wlv.col == 0) + n_skip = v - wlv.vcol; + } + +#ifdef FEAT_PROP_POPUP + // If there the text doesn't reach to the desired column, need to skip + // "skip_cells" cells when virtual text follows. + if ((!wp->w_p_wrap || (lnum == wp->w_topline && wp->w_skipcol > 0)) + && v > wlv.vcol) + skip_cells = v - wlv.vcol; +#endif + + // Adjust for when the inverted text is before the screen, + // and when the start of the inverted text is before the screen. + if (wlv.tocol <= wlv.vcol) + wlv.fromcol = 0; + else if (wlv.fromcol >= 0 && wlv.fromcol < wlv.vcol) + wlv.fromcol = wlv.vcol; + +#ifdef FEAT_LINEBREAK + // When w_skipcol is non-zero, first line needs 'showbreak' + if (wp->w_p_wrap) + wlv.need_showbreak = TRUE; +#endif +#ifdef FEAT_SPELL + // When spell checking a word we need to figure out the start of the + // word and if it's badly spelled or not. + if (has_spell) + { + int len; + colnr_T linecol = (colnr_T)(ptr - line); + hlf_T spell_hlf = HLF_COUNT; + + pos = wp->w_cursor; + wp->w_cursor.lnum = lnum; + wp->w_cursor.col = linecol; + len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf); + + // spell_move_to() may call ml_get() and make "line" invalid + line = ml_get_buf(wp->w_buffer, lnum, FALSE); + ptr = line + linecol; + + if (len == 0 || (int)wp->w_cursor.col > ptr - line) + { + // no bad word found at line start, don't check until end of a + // word + spell_hlf = HLF_COUNT; + word_end = (int)(spell_to_word_end(ptr, wp) - line + 1); + } + else + { + // bad word found, use attributes until end of word + word_end = wp->w_cursor.col + len + 1; + + // Turn index into actual attributes. + if (spell_hlf != HLF_COUNT) + spell_attr = highlight_attr[spell_hlf]; + } + wp->w_cursor = pos; + +# ifdef FEAT_SYN_HL + // Need to restart syntax highlighting for this line. + if (has_syntax) + syntax_start(wp, lnum); +# endif + } +#endif + } + + // Correct highlighting for cursor that can't be disabled. + // Avoids having to check this for each character. + if (wlv.fromcol >= 0) + { + if (noinvcur) + { + if ((colnr_T)wlv.fromcol == wp->w_virtcol) + { + // highlighting starts at cursor, let it start just after the + // cursor + fromcol_prev = wlv.fromcol; + wlv.fromcol = -1; + } + else if ((colnr_T)wlv.fromcol < wp->w_virtcol) + // restart highlighting after the cursor + fromcol_prev = wp->w_virtcol; + } + if (wlv.fromcol >= wlv.tocol) + wlv.fromcol = -1; + } + +#ifdef FEAT_SEARCH_EXTRA + if (!number_only) + { + v = (long)(ptr - line); + area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v, + &line, &screen_search_hl, + &search_attr); + ptr = line + v; // "line" may have been updated + } +#endif + +#ifdef FEAT_SYN_HL + // Cursor line highlighting for 'cursorline' in the current window. + if (wp->w_p_cul && lnum == wp->w_cursor.lnum) + { + // Do not show the cursor line in the text when Visual mode is active, + // because it's not clear what is selected then. + if (!(wp == curwin && VIsual_active) + && wp->w_p_culopt_flags != CULOPT_NBR) + { + wlv.cul_screenline = (wp->w_p_wrap + && (wp->w_p_culopt_flags & CULOPT_SCRLINE)); + + // Only apply CursorLine highlight here when "screenline" is not + // present in 'cursorlineopt'. Otherwise it's done later. + if (!wlv.cul_screenline) + apply_cursorline_highlight(&wlv, sign_present); + else + { + line_attr_save = wlv.line_attr; + margin_columns_win(wp, &left_curline_col, &right_curline_col); + } + area_highlighting = TRUE; + } + } +#endif + + win_line_start(wp, &wlv, FALSE); + + // Repeat for the whole displayed line. + for (;;) + { + char_u *prev_ptr = ptr; +#if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA) + int has_match_conc = 0; // match wants to conceal +#endif +#ifdef FEAT_CONCEAL + int did_decrement_ptr = FALSE; +#endif + + // Skip this quickly when working on the text. + if (wlv.draw_state != WL_LINE) + { +#ifdef FEAT_SYN_HL + if (wlv.cul_screenline) + { + wlv.cul_attr = 0; + wlv.line_attr = line_attr_save; + } +#endif + if (wlv.draw_state == WL_CMDLINE - 1 && wlv.n_extra == 0) + { + wlv.draw_state = WL_CMDLINE; + if (cmdwin_type != 0 && wp == curwin) + { + // Draw the cmdline character. + wlv.n_extra = 1; + wlv.c_extra = cmdwin_type; + wlv.c_final = NUL; + wlv.char_attr = + hl_combine_attr(wlv.wcr_attr, HL_ATTR(HLF_AT)); + } + } +#ifdef FEAT_FOLDING + if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) + { + wlv.draw_state = WL_FOLD; + handle_foldcolumn(wp, &wlv); + } +#endif +#ifdef FEAT_SIGNS + if (wlv.draw_state == WL_SIGN - 1 && wlv.n_extra == 0) + { + // Show the sign column when desired or when using Netbeans. + wlv.draw_state = WL_SIGN; + if (signcolumn_on(wp)) + get_sign_display_info(FALSE, wp, &wlv); + } +#endif + if (wlv.draw_state == WL_NR - 1 && wlv.n_extra == 0) + { + // Show the line number, if desired. + wlv.draw_state = WL_NR; + handle_lnum_col(wp, &wlv, sign_present, num_attr); + } +#ifdef FEAT_LINEBREAK + // Check if 'breakindent' applies and show it. + // May change wlv.draw_state to WL_BRI or WL_BRI - 1. + if (wlv.n_extra == 0) + handle_breakindent(wp, &wlv); +#endif +#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) + if (wlv.draw_state == WL_SBR - 1 && wlv.n_extra == 0) + { + wlv.draw_state = WL_SBR; + handle_showbreak_and_filler(wp, &wlv); + } +#endif + if (wlv.draw_state == WL_LINE - 1 && wlv.n_extra == 0) + { + wlv.draw_state = WL_LINE; + win_line_continue(&wlv); // use wlv.saved_ values + } + } + +#ifdef FEAT_SYN_HL + if (wlv.cul_screenline && wlv.draw_state == WL_LINE + && wlv.vcol >= left_curline_col + && wlv.vcol < right_curline_col) + { + apply_cursorline_highlight(&wlv, sign_present); + } +#endif + + // When still displaying '$' of change command, stop at cursor. + // When only displaying the (relative) line number and that's done, + // stop here. + if (((dollar_vcol >= 0 && wp == curwin + && lnum == wp->w_cursor.lnum + && wlv.vcol >= (long)wp->w_virtcol) + || (number_only && wlv.draw_state > WL_NR)) +#ifdef FEAT_DIFF + && wlv.filler_todo <= 0 +#endif + ) + { + wlv_screen_line(wp, &wlv, TRUE); + // Pretend we have finished updating the window. Except when + // 'cursorcolumn' is set. +#ifdef FEAT_SYN_HL + if (wp->w_p_cuc) + wlv.row = wp->w_cline_row + wp->w_cline_height; + else +#endif + wlv.row = wp->w_height; + break; + } + + if (wlv.draw_state == WL_LINE && (area_highlighting || extra_check)) + { + // handle Visual or match highlighting in this line + if (wlv.vcol == wlv.fromcol + || (has_mbyte && wlv.vcol + 1 == wlv.fromcol + && wlv.n_extra == 0 + && (*mb_ptr2cells)(ptr) > 1) + || ((int)vcol_prev == fromcol_prev + && vcol_prev < wlv.vcol // not at margin + && wlv.vcol < wlv.tocol)) + area_attr = vi_attr; // start highlighting + else if (area_attr != 0 + && (wlv.vcol == wlv.tocol + || (noinvcur && (colnr_T)wlv.vcol == wp->w_virtcol))) + area_attr = 0; // stop highlighting + +#ifdef FEAT_PROP_POPUP + if (text_props != NULL) + { + int pi; + int bcol = (int)(ptr - line); + + if (wlv.n_extra > 0 +# ifdef FEAT_LINEBREAK + && !in_linebreak +# endif + ) + --bcol; // still working on the previous char, e.g. Tab + + // Check if any active property ends. + for (pi = 0; pi < text_props_active; ++pi) + { + int tpi = text_prop_idxs[pi]; + textprop_T *tp = &text_props[tpi]; + + // An inline property ends when after the start column plus + // length. An "above" property ends when used and n_extra + // is zero. + if ((tp->tp_col != MAXCOL + && bcol >= tp->tp_col - 1 + tp->tp_len)) + { + if (pi + 1 < text_props_active) + mch_memmove(text_prop_idxs + pi, + text_prop_idxs + pi + 1, + sizeof(int) + * (text_props_active - (pi + 1))); + --text_props_active; + --pi; +# ifdef FEAT_LINEBREAK + // not exactly right but should work in most cases + if (in_linebreak && syntax_attr == text_prop_attr_comb) + syntax_attr = 0; +# endif + } + } + +# ifdef FEAT_LINEBREAK + if (wlv.n_extra > 0 && in_linebreak) + // not on the next char yet, don't start another prop + --bcol; +# endif + int display_text_first = FALSE; + + // Add any text property that starts in this column. + // With 'nowrap' and not in the first screen line only "below" + // text prop can show. + while (text_prop_next < text_prop_count + && (text_props[text_prop_next].tp_col == MAXCOL + ? ((*ptr == NUL + && (wp->w_p_wrap + || wlv.row == startrow + || (text_props[text_prop_next].tp_flags + & TP_FLAG_ALIGN_BELOW))) + || (bcol == 0 + && (text_props[text_prop_next].tp_flags + & TP_FLAG_ALIGN_ABOVE))) + : bcol >= text_props[text_prop_next].tp_col - 1)) + { + if (text_props[text_prop_next].tp_col == MAXCOL + || bcol <= text_props[text_prop_next].tp_col - 1 + + text_props[text_prop_next].tp_len) + text_prop_idxs[text_props_active++] = text_prop_next; + ++text_prop_next; + } + + if (wlv.n_extra == 0 || !wlv.extra_for_textprop) + { + text_prop_attr = 0; + text_prop_attr_comb = 0; + text_prop_flags = 0; + text_prop_type = NULL; + text_prop_id = 0; + reset_extra_attr = FALSE; + } + if (text_props_active > 0 && wlv.n_extra == 0 + && !display_text_first) + { + int used_tpi = -1; + int used_attr = 0; + int other_tpi = -1; + + text_prop_above = FALSE; + text_prop_follows = FALSE; + + // Sort the properties on priority and/or starting last. + // Then combine the attributes, highest priority last. + sort_text_props(wp->w_buffer, text_props, + text_prop_idxs, text_props_active); + + for (pi = 0; pi < text_props_active; ++pi) + { + int tpi = text_prop_idxs[pi]; + textprop_T *tp = &text_props[tpi]; + proptype_T *pt = text_prop_type_by_id( + wp->w_buffer, tp->tp_type); + + // Only use a text property that can be displayed. + // Skip "after" properties when wrap is off and at the + // end of the window. + if (pt != NULL + && (pt->pt_hl_id > 0 || tp->tp_id < 0) + && tp->tp_id != -MAXCOL + && !(tp->tp_id < 0 + && !wp->w_p_wrap + && (tp->tp_flags & (TP_FLAG_ALIGN_RIGHT + | TP_FLAG_ALIGN_ABOVE + | TP_FLAG_ALIGN_BELOW)) == 0 + && wlv.col >= wp->w_width)) + { + if (tp->tp_col == MAXCOL + && *ptr == NUL + && ((wp->w_p_list && lcs_eol_one > 0 + && (tp->tp_flags + & TP_FLAG_ALIGN_ABOVE) == 0) + || (ptr == line + && !did_line + && (tp->tp_flags + & TP_FLAG_ALIGN_BELOW)))) + { + // skip this prop, first display the '$' after + // the line or display an empty line + text_prop_follows = TRUE; + if (used_tpi < 0) + display_text_first = TRUE; + continue; + } + + if (pt->pt_hl_id > 0) + used_attr = syn_id2attr(pt->pt_hl_id); + text_prop_type = pt; + text_prop_attr = + hl_combine_attr(text_prop_attr, used_attr); + if (used_tpi >= 0 && text_props[used_tpi].tp_id < 0) + other_tpi = used_tpi; + text_prop_flags = pt->pt_flags; + text_prop_id = tp->tp_id; + used_tpi = tpi; + display_text_first = FALSE; + } + } + if (text_prop_id < 0 && used_tpi >= 0 + && -text_prop_id + <= wp->w_buffer->b_textprop_text.ga_len) + { + textprop_T *tp = &text_props[used_tpi]; + char_u *p = ((char_u **)wp->w_buffer + ->b_textprop_text.ga_data)[ + -text_prop_id - 1]; + int above = (tp->tp_flags + & TP_FLAG_ALIGN_ABOVE); + int bail_out = FALSE; + + // reset the ID in the copy to avoid it being used + // again + tp->tp_id = -MAXCOL; + + if (p != NULL) + { + int right = (tp->tp_flags + & TP_FLAG_ALIGN_RIGHT); + int below = (tp->tp_flags + & TP_FLAG_ALIGN_BELOW); + int wrap = (tp->tp_flags & TP_FLAG_WRAP); + int padding = tp->tp_col == MAXCOL + && tp->tp_len > 1 + ? tp->tp_len - 1 : 0; + + // Insert virtual text before the current + // character, or add after the end of the line. + wlv.p_extra = p; + wlv.c_extra = NUL; + wlv.c_final = NUL; + wlv.n_extra = (int)STRLEN(p); + wlv.extra_for_textprop = TRUE; + wlv.extra_attr = hl_combine_attr(wlv.win_attr, + used_attr); + n_attr = mb_charlen(p); + // restore search_attr and area_attr when n_extra + // is down to zero + saved_search_attr = search_attr; + saved_area_attr = area_attr; + search_attr = 0; + area_attr = 0; + text_prop_attr = 0; + text_prop_attr_comb = 0; + if (*ptr == NUL) + // don't combine char attr after EOL + text_prop_flags &= ~PT_FLAG_COMBINE; +#ifdef FEAT_LINEBREAK + if (above || below || right || !wrap) + { + // no 'showbreak' before "below" text property + // or after "above" or "right" text property + wlv.need_showbreak = FALSE; + wlv.dont_use_showbreak = TRUE; + } +#endif + if ((right || above || below || !wrap + || padding > 0) && wp->w_width > 2) + { + char_u *prev_p_extra = wlv.p_extra; + int start_line; + + // Take care of padding, right-align and + // truncation. + // Shared with win_lbr_chartabsize(), must do + // exactly the same. + start_line = text_prop_position(wp, tp, + wlv.vcol, + wlv.col, + &wlv.n_extra, &wlv.p_extra, + &n_attr, &wlv.n_attr_skip, + skip_cells > 0); + if (wlv.p_extra != prev_p_extra) + { + // wlv.p_extra was allocated + vim_free(p_extra_free2); + p_extra_free2 = wlv.p_extra; + } + + if (above) + wlv.vcol_off_tp = wlv.n_extra; + + if (lcs_eol_one < 0 + && wp->w_p_wrap + && wlv.col + + wlv.n_extra - 2 > wp->w_width) + // don't bail out at end of line + text_prop_follows = TRUE; + + // When 'wrap' is off then for "below" we need + // to start a new line explicitly. + if (start_line) + { + draw_screen_line(wp, &wlv); + + // When line got too long for screen break + // here. + if (wlv.row == endrow) + { + ++wlv.row; + break; + } + win_line_start(wp, &wlv, TRUE); + bail_out = TRUE; + } + } + } + + // If the text didn't reach until the first window + // column we need to skip cells. + if (skip_cells > 0) + { + if (wlv.n_extra > skip_cells) + { + wlv.n_extra -= skip_cells; + wlv.p_extra += skip_cells; + wlv.n_attr_skip -= skip_cells; + if (wlv.n_attr_skip < 0) + wlv.n_attr_skip = 0; + skip_cells = 0; + } + else + { + // the whole text is left of the window, drop + // it and advance to the next one + skip_cells -= wlv.n_extra; + wlv.n_extra = 0; + wlv.n_attr_skip = 0; + bail_out = TRUE; + } + } + + // If another text prop follows the condition below at + // the last window column must know. + // If this is an "above" text prop and 'nowrap' the we + // must wrap anyway. + text_prop_above = above; + text_prop_follows |= other_tpi != -1 + && (wp->w_p_wrap + || (text_props[other_tpi].tp_flags + & (TP_FLAG_ALIGN_BELOW | TP_FLAG_ALIGN_RIGHT))); + + if (bail_out) + // starting a new line for "below" + continue; + } + } + else if (text_prop_next < text_prop_count + && text_props[text_prop_next].tp_col == MAXCOL + && ((*ptr != NUL && ptr[mb_ptr2len(ptr)] == NUL) + || (!wp->w_p_wrap + && wlv.col == wp->w_width - 1 + && (text_props[text_prop_next].tp_flags + & TP_FLAG_ALIGN_BELOW)))) + // When at last-but-one character and a text property + // follows after it, we may need to flush the line after + // displaying that character. + // Or when not wrapping and at the rightmost column. + text_prop_follows = TRUE; + } +#endif + +#ifdef FEAT_SEARCH_EXTRA + if (wlv.n_extra == 0) + { + // Check for start/end of 'hlsearch' and other matches. + // After end, check for start/end of next match. + // When another match, have to check for start again. + v = (long)(ptr - line); + search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, + &screen_search_hl, &has_match_conc, + &match_conc, did_line_attr, lcs_eol_one, + &on_last_col); + ptr = line + v; // "line" may have been changed + prev_ptr = ptr; + + // Do not allow a conceal over EOL otherwise EOL will be missed + // and bad things happen. + if (*ptr == NUL) + has_match_conc = 0; + } +#endif + +#ifdef FEAT_DIFF + if (wlv.diff_hlf != (hlf_T)0) + { + // When there is extra text (e.g. virtual text) it gets the + // diff highlighting for the line, but not for changed text. + if (wlv.diff_hlf == HLF_CHD && ptr - line >= change_start + && wlv.n_extra == 0) + wlv.diff_hlf = HLF_TXD; // changed text + if (wlv.diff_hlf == HLF_TXD + && ((ptr - line > change_end && wlv.n_extra == 0) + || (wlv.n_extra > 0 && wlv.extra_for_textprop))) + wlv.diff_hlf = HLF_CHD; // changed line + wlv.line_attr = HL_ATTR(wlv.diff_hlf); + if (wp->w_p_cul && lnum == wp->w_cursor.lnum + && wp->w_p_culopt_flags != CULOPT_NBR + && (!wlv.cul_screenline || (wlv.vcol >= left_curline_col + && wlv.vcol <= right_curline_col))) + wlv.line_attr = hl_combine_attr( + wlv.line_attr, HL_ATTR(HLF_CUL)); + } +#endif + +#ifdef FEAT_SYN_HL + if (extra_check && wlv.n_extra == 0) + { + syntax_attr = 0; +# ifdef FEAT_TERMINAL + if (get_term_attr) + syntax_attr = term_get_attr(wp, lnum, wlv.vcol); +# endif + // Get syntax attribute. + if (has_syntax) + { + // Get the syntax attribute for the character. If there + // is an error, disable syntax highlighting. + save_did_emsg = did_emsg; + did_emsg = FALSE; + + v = (long)(ptr - line); + if (v == prev_syntax_col) + // at same column again + syntax_attr = prev_syntax_attr; + else + { +# ifdef FEAT_SPELL + can_spell = TRUE; +# endif + syntax_attr = get_syntax_attr((colnr_T)v, +# ifdef FEAT_SPELL + has_spell ? &can_spell : +# endif + NULL, FALSE); + prev_syntax_col = v; + prev_syntax_attr = syntax_attr; + } + + if (did_emsg) + { + wp->w_s->b_syn_error = TRUE; + has_syntax = FALSE; + syntax_attr = 0; + } + else + did_emsg = save_did_emsg; +# ifdef SYN_TIME_LIMIT + if (wp->w_s->b_syn_slow) + has_syntax = FALSE; +# endif + + // Need to get the line again, a multi-line regexp may + // have made it invalid. + line = ml_get_buf(wp->w_buffer, lnum, FALSE); + ptr = line + v; + prev_ptr = ptr; +# ifdef FEAT_CONCEAL + // no concealing past the end of the line, it interferes + // with line highlighting + if (*ptr == NUL) + syntax_flags = 0; + else + syntax_flags = get_syntax_info(&syntax_seqnr); +# endif + } + } +# ifdef FEAT_PROP_POPUP + // Combine text property highlight into syntax highlight. + if (text_prop_type != NULL) + { + if (text_prop_flags & PT_FLAG_COMBINE) + syntax_attr = hl_combine_attr(syntax_attr, text_prop_attr); + else + syntax_attr = text_prop_attr; + text_prop_attr_comb = syntax_attr; + } +# endif +#endif + + // Decide which of the highlight attributes to use. + attr_pri = TRUE; +#ifdef LINE_ATTR + if (area_attr != 0) + { + wlv.char_attr = hl_combine_attr(wlv.line_attr, area_attr); + if (!highlight_match) + // let search highlight show in Visual area if possible + wlv.char_attr = hl_combine_attr(search_attr, wlv.char_attr); +# ifdef FEAT_SYN_HL + wlv.char_attr = hl_combine_attr(syntax_attr, wlv.char_attr); +# endif + } + else if (search_attr != 0) + { + wlv.char_attr = hl_combine_attr(wlv.line_attr, search_attr); +# ifdef FEAT_SYN_HL + wlv.char_attr = hl_combine_attr(syntax_attr, wlv.char_attr); +# endif + } + else if (wlv.line_attr != 0 + && ((wlv.fromcol == -10 && wlv.tocol == MAXCOL) + || wlv.vcol < wlv.fromcol + || vcol_prev < fromcol_prev + || wlv.vcol >= wlv.tocol)) + { + // Use wlv.line_attr when not in the Visual or 'incsearch' area + // (area_attr may be 0 when "noinvcur" is set). +# ifdef FEAT_SYN_HL + wlv.char_attr = hl_combine_attr(syntax_attr, wlv.line_attr); +# else + wlv.char_attr = wlv.line_attr; +# endif + attr_pri = FALSE; + } +#else + if (area_attr != 0) + wlv.char_attr = area_attr; + else if (search_attr != 0) + wlv.char_attr = search_attr; +#endif + else + { + attr_pri = FALSE; +#ifdef FEAT_SYN_HL + wlv.char_attr = syntax_attr; +#else + wlv.char_attr = 0; +#endif + } +#ifdef FEAT_PROP_POPUP + // override with text property highlight when "override" is TRUE + if (text_prop_type != NULL && (text_prop_flags & PT_FLAG_OVERRIDE)) + wlv.char_attr = hl_combine_attr(wlv.char_attr, text_prop_attr); +#endif + } + + // combine attribute with 'wincolor' + if (wlv.win_attr != 0) + { + if (wlv.char_attr == 0) + wlv.char_attr = wlv.win_attr; + else + wlv.char_attr = hl_combine_attr(wlv.win_attr, wlv.char_attr); + } + + // Get the next character to put on the screen. + + // The "p_extra" points to the extra stuff that is inserted to + // represent special characters (non-printable stuff) and other + // things. When all characters are the same, c_extra is used. + // If wlv.c_final is set, it will compulsorily be used at the end. + // "p_extra" must end in a NUL to avoid mb_ptr2len() reads past + // "p_extra[n_extra]". + // For the '$' of the 'list' option, n_extra == 1, p_extra == "". + if (wlv.n_extra > 0) + { + if (wlv.c_extra != NUL || (wlv.n_extra == 1 && wlv.c_final != NUL)) + { + c = (wlv.n_extra == 1 && wlv.c_final != NUL) + ? wlv.c_final : wlv.c_extra; + mb_c = c; // doesn't handle non-utf-8 multi-byte! + if (enc_utf8 && utf_char2len(c) > 1) + { + mb_utf8 = TRUE; + u8cc[0] = 0; + c = 0xc0; + } + else + mb_utf8 = FALSE; + } + else + { + c = *wlv.p_extra; + if (has_mbyte) + { + mb_c = c; + if (enc_utf8) + { + // If the UTF-8 character is more than one byte: + // Decode it into "mb_c". + mb_l = utfc_ptr2len(wlv.p_extra); + mb_utf8 = FALSE; + if (mb_l > wlv.n_extra) + mb_l = 1; + else if (mb_l > 1) + { + mb_c = utfc_ptr2char(wlv.p_extra, u8cc); + mb_utf8 = TRUE; + c = 0xc0; + } + } + else + { + // if this is a DBCS character, put it in "mb_c" + mb_l = MB_BYTE2LEN(c); + if (mb_l >= wlv.n_extra) + mb_l = 1; + else if (mb_l > 1) + mb_c = (c << 8) + wlv.p_extra[1]; + } + if (mb_l == 0) // at the NUL at end-of-line + mb_l = 1; + + // If a double-width char doesn't fit display a '>' in the + // last column. + if (( +# ifdef FEAT_RIGHTLEFT + wp->w_p_rl ? (wlv.col <= 0) : +# endif + (wlv.col >= wp->w_width - 1)) + && (*mb_char2cells)(mb_c) == 2) + { + c = '>'; + mb_c = c; + mb_l = 1; + mb_utf8 = FALSE; + multi_attr = HL_ATTR(HLF_AT); +#ifdef FEAT_SYN_HL + if (wlv.cul_attr) + multi_attr = hl_combine_attr( + multi_attr, wlv.cul_attr); +#endif + multi_attr = hl_combine_attr(wlv.win_attr, multi_attr); + + // put the pointer back to output the double-width + // character at the start of the next line. + ++wlv.n_extra; + --wlv.p_extra; + } + else + { + wlv.n_extra -= mb_l - 1; + wlv.p_extra += mb_l - 1; + } + } + ++wlv.p_extra; + } + --wlv.n_extra; +#if defined(FEAT_PROP_POPUP) + if (wlv.n_extra <= 0) + { + // Only restore search_attr and area_attr after "n_extra" in + // the next screen line is also done. + if (wlv.saved_n_extra <= 0) + { + if (search_attr == 0) + search_attr = saved_search_attr; + if (area_attr == 0 && *ptr != NUL) + area_attr = saved_area_attr; + + if (wlv.extra_for_textprop) + // wlv.extra_attr should be used at this position but + // not any further. + reset_extra_attr = TRUE; + } + + wlv.extra_for_textprop = FALSE; + in_linebreak = FALSE; + } +#endif + } + else + { +#ifdef FEAT_LINEBREAK + int c0; +#endif + prev_ptr = ptr; + + // Get a character from the line itself. + c = *ptr; +#ifdef FEAT_LINEBREAK + c0 = *ptr; +#endif +#ifdef FEAT_PROP_POPUP + if (c == NUL) + // text is finished, may display a "below" virtual text + did_line = TRUE; +#endif + + if (has_mbyte) + { + mb_c = c; + if (enc_utf8) + { + // If the UTF-8 character is more than one byte: Decode it + // into "mb_c". + mb_l = utfc_ptr2len(ptr); + mb_utf8 = FALSE; + if (mb_l > 1) + { + mb_c = utfc_ptr2char(ptr, u8cc); + // Overlong encoded ASCII or ASCII with composing char + // is displayed normally, except a NUL. + if (mb_c < 0x80) + { + c = mb_c; +#ifdef FEAT_LINEBREAK + c0 = mb_c; +#endif + } + mb_utf8 = TRUE; + + // At start of the line we can have a composing char. + // Draw it as a space with a composing char. + if (utf_iscomposing(mb_c)) + { + int i; + + for (i = Screen_mco - 1; i > 0; --i) + u8cc[i] = u8cc[i - 1]; + u8cc[0] = mb_c; + mb_c = ' '; + } + } + + if ((mb_l == 1 && c >= 0x80) + || (mb_l >= 1 && mb_c == 0) + || (mb_l > 1 && (!vim_isprintc(mb_c)))) + { + // Illegal UTF-8 byte: display as . + // Non-BMP character : display as ? or fullwidth ?. + transchar_hex(wlv.extra, mb_c); +# ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) // reverse + rl_mirror(wlv.extra); +# endif + wlv.p_extra = wlv.extra; + c = *wlv.p_extra; + mb_c = mb_ptr2char_adv(&wlv.p_extra); + mb_utf8 = (c >= 0x80); + wlv.n_extra = (int)STRLEN(wlv.p_extra); + wlv.c_extra = NUL; + wlv.c_final = NUL; + if (area_attr == 0 && search_attr == 0) + { + n_attr = wlv.n_extra + 1; + wlv.extra_attr = hl_combine_attr( + wlv.win_attr, HL_ATTR(HLF_8)); + saved_attr2 = wlv.char_attr; // save current attr + } + } + else if (mb_l == 0) // at the NUL at end-of-line + mb_l = 1; +#ifdef FEAT_ARABIC + else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c)) + { + // Do Arabic shaping. + int pc, pc1, nc; + int pcc[MAX_MCO]; + + // The idea of what is the previous and next + // character depends on 'rightleft'. + if (wp->w_p_rl) + { + pc = prev_c; + pc1 = prev_c1; + nc = utf_ptr2char(ptr + mb_l); + prev_c1 = u8cc[0]; + } + else + { + pc = utfc_ptr2char(ptr + mb_l, pcc); + nc = prev_c; + pc1 = pcc[0]; + } + prev_c = mb_c; + + mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc); + } + else + prev_c = mb_c; +#endif + } + else // enc_dbcs + { + mb_l = MB_BYTE2LEN(c); + if (mb_l == 0) // at the NUL at end-of-line + mb_l = 1; + else if (mb_l > 1) + { + // We assume a second byte below 32 is illegal. + // Hopefully this is OK for all double-byte encodings! + if (ptr[1] >= 32) + mb_c = (c << 8) + ptr[1]; + else + { + if (ptr[1] == NUL) + { + // head byte at end of line + mb_l = 1; + transchar_nonprint(wp->w_buffer, wlv.extra, c); + } + else + { + // illegal tail byte + mb_l = 2; + STRCPY(wlv.extra, "XX"); + } + wlv.p_extra = wlv.extra; + wlv.n_extra = (int)STRLEN(wlv.extra) - 1; + wlv.c_extra = NUL; + wlv.c_final = NUL; + c = *wlv.p_extra++; + if (area_attr == 0 && search_attr == 0) + { + n_attr = wlv.n_extra + 1; + wlv.extra_attr = hl_combine_attr( + wlv.win_attr, HL_ATTR(HLF_8)); + // save current attr + saved_attr2 = wlv.char_attr; + } + mb_c = c; + } + } + } + // If a double-width char doesn't fit display a '>' in the + // last column; the character is displayed at the start of the + // next line. + if (( +# ifdef FEAT_RIGHTLEFT + wp->w_p_rl ? (wlv.col <= 0) : +# endif + (wlv.col >= wp->w_width - 1)) + && (*mb_char2cells)(mb_c) == 2) + { + c = '>'; + mb_c = c; + mb_utf8 = FALSE; + mb_l = 1; + multi_attr = hl_combine_attr(wlv.win_attr, HL_ATTR(HLF_AT)); + // Put pointer back so that the character will be + // displayed at the start of the next line. + --ptr; +#ifdef FEAT_CONCEAL + did_decrement_ptr = TRUE; +#endif + } + else if (*ptr != NUL) + ptr += mb_l - 1; + + // If a double-width char doesn't fit at the left side display + // a '<' in the first column. Don't do this for unprintable + // characters. + if (n_skip > 0 && mb_l > 1 && wlv.n_extra == 0) + { + wlv.n_extra = 1; + wlv.c_extra = MB_FILLER_CHAR; + wlv.c_final = NUL; + c = ' '; + if (area_attr == 0 && search_attr == 0) + { + n_attr = wlv.n_extra + 1; + wlv.extra_attr = hl_combine_attr( + wlv.win_attr, HL_ATTR(HLF_AT)); + saved_attr2 = wlv.char_attr; // save current attr + } + mb_c = c; + mb_utf8 = FALSE; + mb_l = 1; + } + + } + ++ptr; + + if (extra_check) + { +#ifdef FEAT_SPELL + // Check spelling (unless at the end of the line). + // Only do this when there is no syntax highlighting, the + // @Spell cluster is not used or the current syntax item + // contains the @Spell cluster. + v = (long)(ptr - line); + if (has_spell && v >= word_end && v > cur_checked_col) + { + spell_attr = 0; + // do not calculate cap_col at the end of the line or when + // only white space is following + if (c != 0 && (*skipwhite(prev_ptr) != NUL) && ( +# ifdef FEAT_SYN_HL + !has_syntax || +# endif + can_spell)) + { + char_u *p; + int len; + hlf_T spell_hlf = HLF_COUNT; + + if (has_mbyte) + v -= mb_l - 1; + + // Use nextline[] if possible, it has the start of the + // next line concatenated. + if ((prev_ptr - line) - nextlinecol >= 0) + p = nextline + (prev_ptr - line) - nextlinecol; + else + p = prev_ptr; + cap_col -= (int)(prev_ptr - line); + len = spell_check(wp, p, &spell_hlf, &cap_col, + nochange); + word_end = v + len; + + // In Insert mode only highlight a word that + // doesn't touch the cursor. + if (spell_hlf != HLF_COUNT + && (State & MODE_INSERT) + && wp->w_cursor.lnum == lnum + && wp->w_cursor.col >= + (colnr_T)(prev_ptr - line) + && wp->w_cursor.col < (colnr_T)word_end) + { + spell_hlf = HLF_COUNT; + spell_redraw_lnum = lnum; + } + + if (spell_hlf == HLF_COUNT && p != prev_ptr + && (p - nextline) + len > nextline_idx) + { + // Remember that the good word continues at the + // start of the next line. + checked_lnum = lnum + 1; + checked_col = (int)((p - nextline) + + len - nextline_idx); + } + + // Turn index into actual attributes. + if (spell_hlf != HLF_COUNT) + spell_attr = highlight_attr[spell_hlf]; + + if (cap_col > 0) + { + if (p != prev_ptr + && (p - nextline) + cap_col >= nextline_idx) + { + // Remember that the word in the next line + // must start with a capital. + capcol_lnum = lnum + 1; + cap_col = (int)((p - nextline) + cap_col + - nextline_idx); + } + else + // Compute the actual column. + cap_col += (int)(prev_ptr - line); + } + } + } + if (spell_attr != 0) + { + if (!attr_pri) + wlv.char_attr = hl_combine_attr(wlv.char_attr, + spell_attr); + else + wlv.char_attr = hl_combine_attr(spell_attr, + wlv.char_attr); + } +#endif +#ifdef FEAT_LINEBREAK + // Found last space before word: check for line break. + if (wp->w_p_lbr && c0 == c + && VIM_ISBREAK(c) && !VIM_ISBREAK((int)*ptr)) + { + int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) + : 0; + char_u *p = ptr - (mb_off + 1); + chartabsize_T cts; + + init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, p); +# ifdef FEAT_PROP_POPUP + // do not want virtual text counted here + cts.cts_has_prop_with_text = FALSE; +# endif + wlv.n_extra = win_lbr_chartabsize(&cts, NULL) - 1; + clear_chartabsize_arg(&cts); + + // We have just drawn the showbreak value, no need to add + // space for it again. + if (wlv.vcol == wlv.vcol_sbr) + { + wlv.n_extra -= MB_CHARLEN(get_showbreak_value(wp)); + if (wlv.n_extra < 0) + wlv.n_extra = 0; + } + if (on_last_col && c != TAB) + // Do not continue search/match highlighting over the + // line break, but for TABs the highlighting should + // include the complete width of the character + search_attr = 0; + + if (c == TAB && wlv.n_extra + wlv.col > wp->w_width) +# ifdef FEAT_VARTABS + wlv.n_extra = tabstop_padding(wlv.vcol, + wp->w_buffer->b_p_ts, + wp->w_buffer->b_p_vts_array) - 1; +# else + wlv.n_extra = (int)wp->w_buffer->b_p_ts + - wlv.vcol % (int)wp->w_buffer->b_p_ts - 1; +# endif + + wlv.c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' '; + wlv.c_final = NUL; +# ifdef FEAT_PROP_POPUP + if (wlv.n_extra > 0 && c != TAB) + in_linebreak = TRUE; +# endif + if (VIM_ISWHITE(c)) + { +# ifdef FEAT_CONCEAL + if (c == TAB) + // See "Tab alignment" below. + FIX_FOR_BOGUSCOLS; +# endif + if (!wp->w_p_list) + c = ' '; + } + } +#endif + in_multispace = c == ' ' + && ((ptr > line + 1 && ptr[-2] == ' ') || *ptr == ' '); + if (!in_multispace) + multispace_pos = 0; + + // 'list': Change char 160 to 'nbsp' and space to 'space' + // setting in 'listchars'. But not when the character is + // followed by a composing character (use mb_l to check that). + if (wp->w_p_list + && ((((c == 160 && mb_l == 1) + || (mb_utf8 + && ((mb_c == 160 && mb_l == 2) + || (mb_c == 0x202f && mb_l == 3)))) + && wp->w_lcs_chars.nbsp) + || (c == ' ' + && mb_l == 1 + && (wp->w_lcs_chars.space + || (in_multispace + && wp->w_lcs_chars.multispace != NULL)) + && ptr - line >= leadcol + && ptr - line <= trailcol))) + { + if (in_multispace && wp->w_lcs_chars.multispace != NULL) + { + c = wp->w_lcs_chars.multispace[multispace_pos++]; + if (wp->w_lcs_chars.multispace[multispace_pos] == NUL) + multispace_pos = 0; + } + else + c = (c == ' ') ? wp->w_lcs_chars.space + : wp->w_lcs_chars.nbsp; + if (area_attr == 0 && search_attr == 0) + { + n_attr = 1; + wlv.extra_attr = hl_combine_attr(wlv.win_attr, + HL_ATTR(HLF_8)); + saved_attr2 = wlv.char_attr; // save current attr + } + mb_c = c; + if (enc_utf8 && utf_char2len(c) > 1) + { + mb_utf8 = TRUE; + u8cc[0] = 0; + c = 0xc0; + } + else + mb_utf8 = FALSE; + } + + if (c == ' ' && ((trailcol != MAXCOL && ptr > line + trailcol) + || (leadcol != 0 && ptr < line + leadcol))) + { + if (leadcol != 0 && in_multispace && ptr < line + leadcol + && wp->w_lcs_chars.leadmultispace != NULL) + { + c = wp->w_lcs_chars.leadmultispace[multispace_pos++]; + if (wp->w_lcs_chars.leadmultispace[multispace_pos] + == NUL) + multispace_pos = 0; + } + + else if (ptr > line + trailcol && wp->w_lcs_chars.trail) + c = wp->w_lcs_chars.trail; + + else if (ptr < line + leadcol && wp->w_lcs_chars.lead) + c = wp->w_lcs_chars.lead; + + else if (leadcol != 0 && wp->w_lcs_chars.space) + c = wp->w_lcs_chars.space; + + + if (!attr_pri) + { + n_attr = 1; + wlv.extra_attr = hl_combine_attr(wlv.win_attr, + HL_ATTR(HLF_8)); + saved_attr2 = wlv.char_attr; // save current attr + } + mb_c = c; + if (enc_utf8 && utf_char2len(c) > 1) + { + mb_utf8 = TRUE; + u8cc[0] = 0; + c = 0xc0; + } + else + mb_utf8 = FALSE; + } + } + + // Handling of non-printable characters. + if (!vim_isprintc(c)) + { + // when getting a character from the file, we may have to + // turn it into something else on the way to putting it + // into "ScreenLines". + if (c == TAB && (!wp->w_p_list || wp->w_lcs_chars.tab1)) + { + int tab_len = 0; + long vcol_adjusted = wlv.vcol; // removed showbreak len +#ifdef FEAT_LINEBREAK + char_u *sbr = get_showbreak_value(wp); + + // only adjust the tab_len, when at the first column + // after the showbreak value was drawn + if (*sbr != NUL && wlv.vcol == wlv.vcol_sbr && wp->w_p_wrap) + vcol_adjusted = wlv.vcol - MB_CHARLEN(sbr); +#endif + // tab amount depends on current column +#ifdef FEAT_VARTABS + tab_len = tabstop_padding(vcol_adjusted, + wp->w_buffer->b_p_ts, + wp->w_buffer->b_p_vts_array) - 1; +#else + tab_len = (int)wp->w_buffer->b_p_ts + - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1; +#endif + +#ifdef FEAT_LINEBREAK + if (!wp->w_p_lbr || !wp->w_p_list) +#endif + { + // tab amount depends on current column + wlv.n_extra = tab_len; + } +#ifdef FEAT_LINEBREAK + else + { + char_u *p; + int len; + int i; + int saved_nextra = wlv.n_extra; + +# ifdef FEAT_CONCEAL + if (wlv.vcol_off_co > 0) + // there are characters to conceal + tab_len += wlv.vcol_off_co; + + // boguscols before FIX_FOR_BOGUSCOLS macro from above + if (wp->w_p_list && wp->w_lcs_chars.tab1 + && old_boguscols > 0 + && wlv.n_extra > tab_len) + tab_len += wlv.n_extra - tab_len; +# endif + if (tab_len > 0) + { + // If wlv.n_extra > 0, it gives the number of chars + // to use for a tab, else we need to calculate the + // width for a tab. + int tab2_len = mb_char2len(wp->w_lcs_chars.tab2); + len = tab_len * tab2_len; + if (wp->w_lcs_chars.tab3) + len += mb_char2len(wp->w_lcs_chars.tab3) + - tab2_len; + if (wlv.n_extra > 0) + len += wlv.n_extra - tab_len; + c = wp->w_lcs_chars.tab1; + p = alloc(len + 1); + if (p == NULL) + wlv.n_extra = 0; + else + { + vim_memset(p, ' ', len); + p[len] = NUL; + vim_free(wlv.p_extra_free); + wlv.p_extra_free = p; + for (i = 0; i < tab_len; i++) + { + int lcs = wp->w_lcs_chars.tab2; + + if (*p == NUL) + { + tab_len = i; + break; + } + + // if tab3 is given, use it for the last + // char + if (wp->w_lcs_chars.tab3 + && i == tab_len - 1) + lcs = wp->w_lcs_chars.tab3; + p += mb_char2bytes(lcs, p); + wlv.n_extra += mb_char2len(lcs) + - (saved_nextra > 0 ? 1 : 0); + } + wlv.p_extra = wlv.p_extra_free; +# ifdef FEAT_CONCEAL + // n_extra will be increased by + // FIX_FOX_BOGUSCOLS macro below, so need to + // adjust for that here + if (wlv.vcol_off_co > 0) + wlv.n_extra -= wlv.vcol_off_co; +# endif + } + } + } +#endif +#ifdef FEAT_CONCEAL + { + int vc_saved = wlv.vcol_off_co; + + // Tab alignment should be identical regardless of + // 'conceallevel' value. So tab compensates of all + // previous concealed characters, and thus resets + // vcol_off_co and boguscols accumulated so far in the + // line. Note that the tab can be longer than + // 'tabstop' when there are concealed characters. + FIX_FOR_BOGUSCOLS; + + // Make sure, the highlighting for the tab char will be + // correctly set further below (effectively reverts the + // FIX_FOR_BOGSUCOLS macro). + if (wlv.n_extra == tab_len + vc_saved && wp->w_p_list + && wp->w_lcs_chars.tab1) + tab_len += vc_saved; + } +#endif + mb_utf8 = FALSE; // don't draw as UTF-8 + if (wp->w_p_list) + { + c = (wlv.n_extra == 0 && wp->w_lcs_chars.tab3) + ? wp->w_lcs_chars.tab3 + : wp->w_lcs_chars.tab1; +#ifdef FEAT_LINEBREAK + if (wp->w_p_lbr && wlv.p_extra != NULL + && *wlv.p_extra != NUL) + wlv.c_extra = NUL; // using p_extra from above + else +#endif + wlv.c_extra = wp->w_lcs_chars.tab2; + wlv.c_final = wp->w_lcs_chars.tab3; + n_attr = tab_len + 1; + wlv.extra_attr = hl_combine_attr(wlv.win_attr, + HL_ATTR(HLF_8)); + saved_attr2 = wlv.char_attr; // save current attr + mb_c = c; + if (enc_utf8 && utf_char2len(c) > 1) + { + mb_utf8 = TRUE; + u8cc[0] = 0; + c = 0xc0; + } + } + else + { + wlv.c_final = NUL; + wlv.c_extra = ' '; + c = ' '; + } + } + else if (c == NUL + && wlv.n_extra == 0 + && (wp->w_p_list + || ((wlv.fromcol >= 0 || fromcol_prev >= 0) + && wlv.tocol > wlv.vcol + && VIsual_mode != Ctrl_V + && ( +# ifdef FEAT_RIGHTLEFT + wp->w_p_rl ? (wlv.col >= 0) : +# endif + (wlv.col < wp->w_width)) + && !(noinvcur + && lnum == wp->w_cursor.lnum + && (colnr_T)wlv.vcol == wp->w_virtcol))) + && lcs_eol_one > 0) + { + // Display a '$' after the line or highlight an extra + // character if the line break is included. +#if defined(FEAT_DIFF) || defined(LINE_ATTR) + // For a diff line the highlighting continues after the + // "$". + if ( +# ifdef FEAT_DIFF + wlv.diff_hlf == (hlf_T)0 +# ifdef LINE_ATTR + && +# endif +# endif +# ifdef LINE_ATTR + wlv.line_attr == 0 +# endif + ) +#endif + { + // In virtualedit, visual selections may extend + // beyond end of line. + if (!(area_highlighting && virtual_active() + && wlv.tocol != MAXCOL + && wlv.vcol < wlv.tocol)) + wlv.p_extra = at_end_str; + wlv.n_extra = 0; + } + if (wp->w_p_list && wp->w_lcs_chars.eol > 0) + c = wp->w_lcs_chars.eol; + else + c = ' '; + lcs_eol_one = -1; + --ptr; // put it back at the NUL + if (!attr_pri) + { + wlv.extra_attr = hl_combine_attr(wlv.win_attr, + HL_ATTR(HLF_AT)); + n_attr = 1; + } + mb_c = c; + if (enc_utf8 && utf_char2len(c) > 1) + { + mb_utf8 = TRUE; + u8cc[0] = 0; + c = 0xc0; + } + else + mb_utf8 = FALSE; // don't draw as UTF-8 + } + else if (c != NUL) + { + wlv.p_extra = transchar_buf(wp->w_buffer, c); + if (wlv.n_extra == 0) + wlv.n_extra = byte2cells(c) - 1; +#ifdef FEAT_RIGHTLEFT + if ((dy_flags & DY_UHEX) && wp->w_p_rl) + rl_mirror(wlv.p_extra); // reverse "<12>" +#endif + wlv.c_extra = NUL; + wlv.c_final = NUL; +#ifdef FEAT_LINEBREAK + if (wp->w_p_lbr) + { + char_u *p; + + c = *wlv.p_extra; + p = alloc(wlv.n_extra + 1); + vim_memset(p, ' ', wlv.n_extra); + STRNCPY(p, wlv.p_extra + 1, STRLEN(wlv.p_extra) - 1); + p[wlv.n_extra] = NUL; + vim_free(wlv.p_extra_free); + wlv.p_extra_free = wlv.p_extra = p; + } + else +#endif + { + wlv.n_extra = byte2cells(c) - 1; + c = *wlv.p_extra++; + } + if (!attr_pri) + { + n_attr = wlv.n_extra + 1; + wlv.extra_attr = hl_combine_attr(wlv.win_attr, + HL_ATTR(HLF_8)); + saved_attr2 = wlv.char_attr; // save current attr + } + mb_utf8 = FALSE; // don't draw as UTF-8 + } + else if (VIsual_active + && (VIsual_mode == Ctrl_V + || VIsual_mode == 'v') + && virtual_active() + && wlv.tocol != MAXCOL + && wlv.vcol < wlv.tocol + && ( +#ifdef FEAT_RIGHTLEFT + wp->w_p_rl ? (wlv.col >= 0) : +#endif + (wlv.col < wp->w_width))) + { + c = ' '; + --ptr; // put it back at the NUL + } +#if defined(LINE_ATTR) + else if (( +# ifdef FEAT_DIFF + wlv.diff_hlf != (hlf_T)0 || +# endif +# ifdef FEAT_TERMINAL + wlv.win_attr != 0 || +# endif + wlv.line_attr != 0 + ) && ( +# ifdef FEAT_RIGHTLEFT + wp->w_p_rl ? (wlv.col >= 0) : +# endif + (wlv.col +# ifdef FEAT_CONCEAL + - wlv.boguscols +# endif + < wp->w_width))) + { + // Highlight until the right side of the window + c = ' '; + --ptr; // put it back at the NUL + + // Remember we do the char for line highlighting. + ++did_line_attr; + + // don't do search HL for the rest of the line + if (wlv.line_attr != 0 && wlv.char_attr == search_attr + && (did_line_attr > 1 + || (wp->w_p_list && + wp->w_lcs_chars.eol > 0))) + wlv.char_attr = wlv.line_attr; +# ifdef FEAT_DIFF + if (wlv.diff_hlf == HLF_TXD) + { + wlv.diff_hlf = HLF_CHD; + if (vi_attr == 0 || wlv.char_attr != vi_attr) + { + wlv.char_attr = HL_ATTR(wlv.diff_hlf); + if (wp->w_p_cul && lnum == wp->w_cursor.lnum + && wp->w_p_culopt_flags != CULOPT_NBR + && (!wlv.cul_screenline + || (wlv.vcol >= left_curline_col + && wlv.vcol <= right_curline_col))) + wlv.char_attr = hl_combine_attr( + wlv.char_attr, HL_ATTR(HLF_CUL)); + } + } +# endif +# ifdef FEAT_TERMINAL + if (wlv.win_attr != 0) + { + wlv.char_attr = wlv.win_attr; + if (wp->w_p_cul && lnum == wp->w_cursor.lnum + && wp->w_p_culopt_flags != CULOPT_NBR) + { + if (!wlv.cul_screenline + || (wlv.vcol >= left_curline_col + && wlv.vcol <= right_curline_col)) + wlv.char_attr = hl_combine_attr( + wlv.char_attr, HL_ATTR(HLF_CUL)); + } + else if (wlv.line_attr) + wlv.char_attr = hl_combine_attr( + wlv.char_attr, wlv.line_attr); + } +# endif + } +#endif + } + +#ifdef FEAT_CONCEAL + if ( wp->w_p_cole > 0 + && (wp != curwin || lnum != wp->w_cursor.lnum + || conceal_cursor_line(wp)) + && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0) + && !(lnum_in_visual_area + && vim_strchr(wp->w_p_cocu, 'v') == NULL)) + { + wlv.char_attr = conceal_attr; + if (((prev_syntax_id != syntax_seqnr + && (syntax_flags & HL_CONCEAL) != 0) + || has_match_conc > 1) + && (syn_get_sub_char() != NUL + || (has_match_conc && match_conc) + || wp->w_p_cole == 1) + && wp->w_p_cole != 3) + { + // First time at this concealed item: display one + // character. + if (has_match_conc && match_conc) + c = match_conc; + else if (syn_get_sub_char() != NUL) + c = syn_get_sub_char(); + else if (wp->w_lcs_chars.conceal != NUL) + c = wp->w_lcs_chars.conceal; + else + c = ' '; + + prev_syntax_id = syntax_seqnr; + + if (wlv.n_extra > 0) + wlv.vcol_off_co += wlv.n_extra; + wlv.vcol += wlv.n_extra; + if (wp->w_p_wrap && wlv.n_extra > 0) + { +# ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + { + wlv.col -= wlv.n_extra; + wlv.boguscols -= wlv.n_extra; + } + else +# endif + { + wlv.boguscols += wlv.n_extra; + wlv.col += wlv.n_extra; + } + } + wlv.n_extra = 0; + n_attr = 0; + } + else if (n_skip == 0) + { + is_concealing = TRUE; + n_skip = 1; + } + mb_c = c; + if (enc_utf8 && utf_char2len(c) > 1) + { + mb_utf8 = TRUE; + u8cc[0] = 0; + c = 0xc0; + } + else + mb_utf8 = FALSE; // don't draw as UTF-8 + } + else + { + prev_syntax_id = 0; + is_concealing = FALSE; + } + + if (n_skip > 0 && did_decrement_ptr) + // not showing the '>', put pointer back to avoid getting stuck + ++ptr; + +#endif // FEAT_CONCEAL + } + +#ifdef FEAT_CONCEAL + // In the cursor line and we may be concealing characters: correct + // the cursor column when we reach its position. + if (!did_wcol && wlv.draw_state == WL_LINE + && wp == curwin && lnum == wp->w_cursor.lnum + && conceal_cursor_line(wp) + && (int)wp->w_virtcol <= wlv.vcol + n_skip) + { +# ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + wp->w_wcol = wp->w_width - wlv.col + wlv.boguscols - 1; + else +# endif + wp->w_wcol = wlv.col - wlv.boguscols; + wp->w_wrow = wlv.row; + did_wcol = TRUE; + curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; +# ifdef FEAT_PROP_POPUP + curwin->w_flags &= ~(WFLAG_WCOL_OFF_ADDED | WFLAG_WROW_OFF_ADDED); +# endif + } +#endif + + // Use "wlv.extra_attr", but don't override visual selection + // highlighting, unless text property overrides. + // Don't use "wlv.extra_attr" until wlv.n_attr_skip is zero. + if (wlv.n_attr_skip == 0 && n_attr > 0 + && wlv.draw_state == WL_LINE + && (!attr_pri +#ifdef FEAT_PROP_POPUP + || (text_prop_flags & PT_FLAG_OVERRIDE) +#endif + )) + { +#ifdef LINE_ATTR + if (wlv.line_attr) + wlv.char_attr = hl_combine_attr(wlv.line_attr, wlv.extra_attr); + else +#endif + wlv.char_attr = wlv.extra_attr; +#ifdef FEAT_PROP_POPUP + if (reset_extra_attr) + { + reset_extra_attr = FALSE; + wlv.extra_attr = 0; + } +#endif + } + +#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) + // XIM don't send preedit_start and preedit_end, but they send + // preedit_changed and commit. Thus Vim can't set "im_is_active", use + // im_is_preediting() here. + if (p_imst == IM_ON_THE_SPOT + && xic != NULL + && lnum == wp->w_cursor.lnum + && (State & MODE_INSERT) + && !p_imdisable + && im_is_preediting() + && wlv.draw_state == WL_LINE) + { + colnr_T tcol; + + if (preedit_end_col == MAXCOL) + getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL); + else + tcol = preedit_end_col; + if ((long)preedit_start_col <= wlv.vcol && wlv.vcol < (long)tcol) + { + if (feedback_old_attr < 0) + { + feedback_col = 0; + feedback_old_attr = wlv.char_attr; + } + wlv.char_attr = im_get_feedback_attr(feedback_col); + if (wlv.char_attr < 0) + wlv.char_attr = feedback_old_attr; + feedback_col++; + } + else if (feedback_old_attr >= 0) + { + wlv.char_attr = feedback_old_attr; + feedback_old_attr = -1; + feedback_col = 0; + } + } +#endif + // Handle the case where we are in column 0 but not on the first + // character of the line and the user wants us to show us a + // special character (via 'listchars' option "precedes:". + if (lcs_prec_todo != NUL + && wp->w_p_list + && (wp->w_p_wrap ? (wp->w_skipcol > 0 && wlv.row == 0) + : wp->w_leftcol > 0) +#ifdef FEAT_DIFF + && wlv.filler_todo <= 0 +#endif + && wlv.draw_state > WL_NR + && c != NUL) + { + c = wp->w_lcs_chars.prec; + lcs_prec_todo = NUL; + if (has_mbyte && (*mb_char2cells)(mb_c) > 1) + { + // Double-width character being overwritten by the "precedes" + // character, need to fill up half the character. + wlv.c_extra = MB_FILLER_CHAR; + wlv.c_final = NUL; + wlv.n_extra = 1; + n_attr = 2; + wlv.extra_attr = + hl_combine_attr(wlv.win_attr, HL_ATTR(HLF_AT)); + } + mb_c = c; + if (enc_utf8 && utf_char2len(c) > 1) + { + mb_utf8 = TRUE; + u8cc[0] = 0; + c = 0xc0; + } + else + mb_utf8 = FALSE; // don't draw as UTF-8 + if (!attr_pri) + { + saved_attr3 = wlv.char_attr; // save current attr + wlv.char_attr = hl_combine_attr(wlv.win_attr, HL_ATTR(HLF_AT)); + n_attr3 = 1; + } + } + + // At end of the text line or just after the last character. + if ((c == NUL +#if defined(LINE_ATTR) + || did_line_attr == 1 +#endif + ) && wlv.eol_hl_off == 0) + { +#ifdef FEAT_SEARCH_EXTRA + // flag to indicate whether prevcol equals startcol of search_hl or + // one of the matches + int prevcol_hl_flag = get_prevcol_hl_flag(wp, &screen_search_hl, + (long)(ptr - line) - (c == NUL)); +#endif + // Invert at least one char, used for Visual and empty line or + // highlight match at end of line. If it's beyond the last + // char on the screen, just overwrite that one (tricky!) Not + // needed when a '$' was displayed for 'list'. + if (wp->w_lcs_chars.eol == lcs_eol_one + && ((area_attr != 0 && wlv.vcol == wlv.fromcol + && (VIsual_mode != Ctrl_V + || lnum == VIsual.lnum + || lnum == curwin->w_cursor.lnum) + && c == NUL) +#ifdef FEAT_SEARCH_EXTRA + // highlight 'hlsearch' match at end of line + || (prevcol_hl_flag +# ifdef FEAT_SYN_HL + && !(wp->w_p_cul && lnum == wp->w_cursor.lnum + && !(wp == curwin && VIsual_active)) +# endif +# ifdef FEAT_DIFF + && wlv.diff_hlf == (hlf_T)0 +# endif +# if defined(LINE_ATTR) + && did_line_attr <= 1 +# endif + ) +#endif + )) + { + int n = 0; + +#ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + { + if (wlv.col < 0) + n = 1; + } + else +#endif + { + if (wlv.col >= wp->w_width) + n = -1; + } + if (n != 0) + { + // At the window boundary, highlight the last character + // instead (better than nothing). + wlv.off += n; + wlv.col += n; + } + else + { + // Add a blank character to highlight. + ScreenLines[wlv.off] = ' '; + if (enc_utf8) + ScreenLinesUC[wlv.off] = 0; + } +#ifdef FEAT_SEARCH_EXTRA + if (area_attr == 0) + { + // Use attributes from match with highest priority among + // 'search_hl' and the match list. + get_search_match_hl(wp, &screen_search_hl, + (long)(ptr - line), &wlv.char_attr); + } +#endif + ScreenAttrs[wlv.off] = wlv.char_attr; + ScreenCols[wlv.off] = MAXCOL; +#ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + { + --wlv.col; + --wlv.off; + } + else +#endif + { + ++wlv.col; + ++wlv.off; + } + ++wlv.vcol; + wlv.eol_hl_off = 1; + } + } + + // At end of the text line. + if (c == NUL) + { +#ifdef FEAT_PROP_POPUP + if (text_prop_follows) + { + // Put the pointer back to the NUL. + --ptr; + c = ' '; + } + else +#endif + { + draw_screen_line(wp, &wlv); + + // Update w_cline_height and w_cline_folded if the cursor line + // was updated (saves a call to plines() later). + if (wp == curwin && lnum == curwin->w_cursor.lnum) + { + curwin->w_cline_row = startrow; + curwin->w_cline_height = wlv.row - startrow; +#ifdef FEAT_FOLDING + curwin->w_cline_folded = FALSE; +#endif + curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); + } + break; + } + } + + // Show "extends" character from 'listchars' if beyond the line end and + // 'list' is set. + if (wp->w_lcs_chars.ext != NUL + && wlv.draw_state == WL_LINE + && wp->w_p_list + && !wp->w_p_wrap +#ifdef FEAT_DIFF + && wlv.filler_todo <= 0 +#endif + && ( +#ifdef FEAT_RIGHTLEFT + wp->w_p_rl ? wlv.col == 0 : +#endif + wlv.col == wp->w_width - 1) + && (*ptr != NUL + || lcs_eol_one > 0 + || (wlv.n_extra > 0 && (wlv.c_extra != NUL + || *wlv.p_extra != NUL)))) + { + c = wp->w_lcs_chars.ext; + wlv.char_attr = hl_combine_attr(wlv.win_attr, HL_ATTR(HLF_AT)); + mb_c = c; + if (enc_utf8 && utf_char2len(c) > 1) + { + mb_utf8 = TRUE; + u8cc[0] = 0; + c = 0xc0; + } + else + mb_utf8 = FALSE; + } + +#ifdef FEAT_SYN_HL + // advance to the next 'colorcolumn' + if (wlv.draw_color_col) + wlv.draw_color_col = advance_color_col(VCOL_HLC, &wlv.color_cols); + + // Highlight the cursor column if 'cursorcolumn' is set. But don't + // highlight the cursor position itself. + // Also highlight the 'colorcolumn' if it is different than + // 'cursorcolumn' + // Also highlight the 'colorcolumn' if 'breakindent' and/or 'showbreak' + // options are set + vcol_save_attr = -1; + if (((wlv.draw_state == WL_LINE + || wlv.draw_state == WL_BRI + || wlv.draw_state == WL_SBR) + && !lnum_in_visual_area + && search_attr == 0 + && area_attr == 0) +# ifdef FEAT_DIFF + && wlv.filler_todo <= 0 +# endif + ) + { + if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol + && lnum != wp->w_cursor.lnum) + { + vcol_save_attr = wlv.char_attr; + wlv.char_attr = hl_combine_attr(wlv.char_attr, + HL_ATTR(HLF_CUC)); + } + else if (wlv.draw_color_col && VCOL_HLC == *wlv.color_cols) + { + vcol_save_attr = wlv.char_attr; + wlv.char_attr = hl_combine_attr(wlv.char_attr, HL_ATTR(HLF_MC)); + } + } +#endif + + // Store character to be displayed. + // Skip characters that are left of the screen for 'nowrap'. + vcol_prev = wlv.vcol; + if (wlv.draw_state < WL_LINE || n_skip <= 0) + { + // Store the character. +#if defined(FEAT_RIGHTLEFT) + if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1) + { + // A double-wide character is: put first half in left cell. + --wlv.off; + --wlv.col; + } +#endif + ScreenLines[wlv.off] = c; + if (enc_dbcs == DBCS_JPNU) + { + if ((mb_c & 0xff00) == 0x8e00) + ScreenLines[wlv.off] = 0x8e; + ScreenLines2[wlv.off] = mb_c & 0xff; + } + else if (enc_utf8) + { + if (mb_utf8) + { + int i; + + ScreenLinesUC[wlv.off] = mb_c; + if ((c & 0xff) == 0) + ScreenLines[wlv.off] = 0x80; // avoid storing zero + for (i = 0; i < Screen_mco; ++i) + { + ScreenLinesC[i][wlv.off] = u8cc[i]; + if (u8cc[i] == 0) + break; + } + } + else + ScreenLinesUC[wlv.off] = 0; + } + if (multi_attr) + { + ScreenAttrs[wlv.off] = multi_attr; + multi_attr = 0; + } + else + ScreenAttrs[wlv.off] = wlv.char_attr; + + ScreenCols[wlv.off] = (colnr_T)(prev_ptr - line); + + if (has_mbyte && (*mb_char2cells)(mb_c) > 1) + { + // Need to fill two screen columns. + ++wlv.off; + ++wlv.col; + if (enc_utf8) + // UTF-8: Put a 0 in the second screen char. + ScreenLines[wlv.off] = 0; + else + // DBCS: Put second byte in the second screen char. + ScreenLines[wlv.off] = mb_c & 0xff; + if (wlv.draw_state > WL_NR +#ifdef FEAT_DIFF + && wlv.filler_todo <= 0 +#endif + ) + ++wlv.vcol; + // When "wlv.tocol" is halfway a character, set it to the end + // of the character, otherwise highlighting won't stop. + if (wlv.tocol == wlv.vcol) + ++wlv.tocol; + + ScreenCols[wlv.off] = (colnr_T)(prev_ptr - line); + +#ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + { + // now it's time to backup one cell + --wlv.off; + --wlv.col; + } +#endif + } +#ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + { + --wlv.off; + --wlv.col; + } + else +#endif + { + ++wlv.off; + ++wlv.col; + } + } +#ifdef FEAT_CONCEAL + else if (wp->w_p_cole > 0 && is_concealing) + { + --n_skip; + ++wlv.vcol_off_co; + if (wlv.n_extra > 0) + wlv.vcol_off_co += wlv.n_extra; + if (wp->w_p_wrap) + { + // Special voodoo required if 'wrap' is on. + // + // Advance the column indicator to force the line + // drawing to wrap early. This will make the line + // take up the same screen space when parts are concealed, + // so that cursor line computations aren't messed up. + // + // To avoid the fictitious advance of 'wlv.col' causing + // trailing junk to be written out of the screen line + // we are building, 'boguscols' keeps track of the number + // of bad columns we have advanced. + if (wlv.n_extra > 0) + { + wlv.vcol += wlv.n_extra; +# ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + { + wlv.col -= wlv.n_extra; + wlv.boguscols -= wlv.n_extra; + } + else +# endif + { + wlv.col += wlv.n_extra; + wlv.boguscols += wlv.n_extra; + } + wlv.n_extra = 0; + n_attr = 0; + } + + + if (has_mbyte && (*mb_char2cells)(mb_c) > 1) + { + // Need to fill two screen columns. +# ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + { + --wlv.boguscols; + --wlv.col; + } + else +# endif + { + ++wlv.boguscols; + ++wlv.col; + } + } + +# ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + { + --wlv.boguscols; + --wlv.col; + } + else +# endif + { + ++wlv.boguscols; + ++wlv.col; + } + } + else + { + if (wlv.n_extra > 0) + { + wlv.vcol += wlv.n_extra; + wlv.n_extra = 0; + n_attr = 0; + } + } + + } +#endif // FEAT_CONCEAL + else + --n_skip; + + // Only advance the "wlv.vcol" when after the 'number' or + // 'relativenumber' column. + if (wlv.draw_state > WL_NR +#ifdef FEAT_DIFF + && wlv.filler_todo <= 0 +#endif + ) + ++wlv.vcol; + +#ifdef FEAT_SYN_HL + if (vcol_save_attr >= 0) + wlv.char_attr = vcol_save_attr; +#endif + + // restore attributes after "precedes" in 'listchars' + if (wlv.draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0) + wlv.char_attr = saved_attr3; + + // restore attributes after last 'listchars' or 'number' char + if (n_attr > 0 && wlv.draw_state == WL_LINE + && wlv.n_attr_skip == 0 && --n_attr == 0) + wlv.char_attr = saved_attr2; + if (wlv.n_attr_skip > 0) + --wlv.n_attr_skip; + + // At end of screen line and there is more to come: Display the line + // so far. If there is no more to display it is caught above. + if (( +#ifdef FEAT_RIGHTLEFT + wp->w_p_rl ? (wlv.col < 0) : +#endif + (wlv.col >= wp->w_width)) + && (wlv.draw_state != WL_LINE + || *ptr != NUL +#ifdef FEAT_DIFF + || wlv.filler_todo > 0 +#endif +#ifdef FEAT_PROP_POPUP + || text_prop_above || text_prop_follows +#endif + || (wp->w_p_list && wp->w_lcs_chars.eol != NUL + && wlv.p_extra != at_end_str) + || (wlv.n_extra != 0 && (wlv.c_extra != NUL + || *wlv.p_extra != NUL))) + ) + { +#ifdef FEAT_CONCEAL + wlv.col -= wlv.boguscols; + wlv_screen_line(wp, &wlv, FALSE); + wlv.col += wlv.boguscols; + wlv.boguscols = 0; + wlv.vcol_off_co = 0; +#else + wlv_screen_line(wp, &wlv, FALSE); +#endif + ++wlv.row; + ++wlv.screen_row; + + // When not wrapping and finished diff lines, or when displayed + // '$' and highlighting until last column, break here. + if (((!wp->w_p_wrap +#ifdef FEAT_DIFF + && wlv.filler_todo <= 0 +#endif +#ifdef FEAT_PROP_POPUP + && !text_prop_above +#endif + ) || lcs_eol_one == -1) +#ifdef FEAT_PROP_POPUP + && !text_prop_follows +#endif + ) + break; +#ifdef FEAT_PROP_POPUP + if (!wp->w_p_wrap && text_prop_follows && !text_prop_above) + { + // do not output more of the line, only the "below" prop + ptr += STRLEN(ptr); +# ifdef FEAT_LINEBREAK + wlv.dont_use_showbreak = TRUE; +# endif + } +#endif + + // When the window is too narrow draw all "@" lines. + if (wlv.draw_state != WL_LINE +#ifdef FEAT_DIFF + && wlv.filler_todo <= 0 +#endif + ) + { + win_draw_end(wp, '@', ' ', TRUE, wlv.row, wp->w_height, HLF_AT); + draw_vsep_win(wp, wlv.row); + wlv.row = endrow; + } + + // When line got too long for screen break here. + if (wlv.row == endrow) + { + ++wlv.row; + break; + } + + if (screen_cur_row == wlv.screen_row - 1 +#ifdef FEAT_DIFF + && wlv.filler_todo <= 0 +#endif +#ifdef FEAT_PROP_POPUP + && !text_prop_above && !text_prop_follows +#endif + && wp->w_width == Columns) + { + // Remember that the line wraps, used for modeless copy. + LineWraps[wlv.screen_row - 1] = TRUE; + + // Special trick to make copy/paste of wrapped lines work with + // xterm/screen: write an extra character beyond the end of + // the line. This will work with all terminal types + // (regardless of the xn,am settings). + // Only do this on a fast tty. + // Only do this if the cursor is on the current line + // (something has been written in it). + // Don't do this for the GUI. + // Don't do this for double-width characters. + // Don't do this for a window not at the right screen border. + if (p_tf +#ifdef FEAT_GUI + && !gui.in_use +#endif + && !(has_mbyte + && ((*mb_off2cells)(LineOffset[wlv.screen_row], + LineOffset[wlv.screen_row] + screen_Columns) + == 2 + || (*mb_off2cells)( + LineOffset[wlv.screen_row - 1] + + (int)Columns - 2, + LineOffset[wlv.screen_row] + + screen_Columns) == 2))) + { + // First make sure we are at the end of the screen line, + // then output the same character again to let the + // terminal know about the wrap. If the terminal doesn't + // auto-wrap, we overwrite the character. + if (screen_cur_col != wp->w_width) + screen_char(LineOffset[wlv.screen_row - 1] + + (unsigned)Columns - 1, + wlv.screen_row - 1, (int)(Columns - 1)); + + // When there is a multi-byte character, just output a + // space to keep it simple. + if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[ + wlv.screen_row - 1] + (Columns - 1)]) > 1) + out_char(' '); + else + out_char(ScreenLines[LineOffset[wlv.screen_row - 1] + + (Columns - 1)]); + // force a redraw of the first char on the next line + ScreenAttrs[LineOffset[wlv.screen_row]] = (sattr_T)-1; + screen_start(); // don't know where cursor is now + } + } + + win_line_start(wp, &wlv, TRUE); + + lcs_prec_todo = wp->w_lcs_chars.prec; +#ifdef FEAT_LINEBREAK + if (!wlv.dont_use_showbreak +# ifdef FEAT_DIFF + && wlv.filler_todo <= 0 +# endif + ) + wlv.need_showbreak = TRUE; +#endif +#ifdef FEAT_DIFF + --wlv.filler_todo; + // When the filler lines are actually below the last line of the + // file, don't draw the line itself, break here. + if (wlv.filler_todo == 0 && wp->w_botfill) + break; +#endif + } + + } // for every character in the line + +#ifdef FEAT_SPELL + // After an empty line check first word for capital. + if (*skipwhite(line) == NUL) + { + capcol_lnum = lnum + 1; + cap_col = 0; + } +#endif +#ifdef FEAT_PROP_POPUP + vim_free(text_props); + vim_free(text_prop_idxs); + vim_free(p_extra_free2); +#endif + + vim_free(wlv.p_extra_free); + return wlv.row; +} diff --git a/src/drawscreen.c b/src/drawscreen.c new file mode 100644 index 0000000..13892bb --- /dev/null +++ b/src/drawscreen.c @@ -0,0 +1,3352 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * drawscreen.c: Code for updating all the windows on the screen. + * This is the top level, drawline.c is the middle and screen.c the lower + * level. + * + * update_screen() is the function that updates all windows and status lines. + * It is called form the main loop when must_redraw is non-zero. It may be + * called from other places when an immediate screen update is needed. + * + * The part of the buffer that is displayed in a window is set with: + * - w_topline (first buffer line in window) + * - w_topfill (filler lines above the first line) + * - w_leftcol (leftmost window cell in window), + * - w_skipcol (skipped window cells of first line) + * + * Commands that only move the cursor around in a window, do not need to take + * action to update the display. The main loop will check if w_topline is + * valid and update it (scroll the window) when needed. + * + * Commands that scroll a window change w_topline and must call + * check_cursor() to move the cursor into the visible part of the window, and + * call redraw_later(UPD_VALID) to have the window displayed by update_screen() + * later. + * + * Commands that change text in the buffer must call changed_bytes() or + * changed_lines() to mark the area that changed and will require updating + * later. The main loop will call update_screen(), which will update each + * window that shows the changed buffer. This assumes text above the change + * can remain displayed as it is. Text after the change may need updating for + * scrolling, folding and syntax highlighting. + * + * Commands that change how a window is displayed (e.g., setting 'list') or + * invalidate the contents of a window in another way (e.g., change fold + * settings), must call redraw_later(UPD_NOT_VALID) to have the whole window + * redisplayed by update_screen() later. + * + * Commands that change how a buffer is displayed (e.g., setting 'tabstop') + * must call redraw_curbuf_later(UPD_NOT_VALID) to have all the windows for the + * buffer redisplayed by update_screen() later. + * + * Commands that change highlighting and possibly cause a scroll too must call + * redraw_later(UPD_SOME_VALID) to update the whole window but still use + * scrolling to avoid redrawing everything. But the length of displayed lines + * must not change, use UPD_NOT_VALID then. + * + * Commands that move the window position must call redraw_later(UPD_NOT_VALID). + * TODO: should minimize redrawing by scrolling when possible. + * + * Commands that change everything (e.g., resizing the screen) must call + * redraw_all_later(UPD_NOT_VALID) or redraw_all_later(UPD_CLEAR). + * + * Things that are handled indirectly: + * - When messages scroll the screen up, msg_scrolled will be set and + * update_screen() called to redraw. + */ + +#include "vim.h" + +static void win_update(win_T *wp); +#ifdef FEAT_STL_OPT +static void redraw_custom_statusline(win_T *wp); +#endif +#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) +static int did_update_one_window; +#endif + +/* + * Based on the current value of curwin->w_topline, transfer a screenfull + * of stuff from Filemem to ScreenLines[], and update curwin->w_botline. + * Return OK when the screen was updated, FAIL if it was not done. + */ + int +update_screen(int type_arg) +{ + int type = type_arg; + win_T *wp; + static int did_intro = FALSE; +#ifdef FEAT_GUI + int did_one = FALSE; + int did_undraw = FALSE; + int gui_cursor_col = 0; + int gui_cursor_row = 0; +#endif + int no_update = FALSE; + int save_pum_will_redraw = pum_will_redraw; + + // Don't do anything if the screen structures are (not yet) valid. + if (!screen_valid(TRUE)) + return FAIL; + + if (type == UPD_VALID_NO_UPDATE) + { + no_update = TRUE; + type = 0; + } + +#ifdef FEAT_EVAL + { + buf_T *buf; + + // Before updating the screen, notify any listeners of changed text. + FOR_ALL_BUFFERS(buf) + invoke_listeners(buf); + } +#endif + +#ifdef FEAT_DIFF + // May have postponed updating diffs. + if (need_diff_redraw) + diff_redraw(TRUE); +#endif + + if (must_redraw) + { + if (type < must_redraw) // use maximal type + type = must_redraw; + + // must_redraw is reset here, so that when we run into some weird + // reason to redraw while busy redrawing (e.g., asynchronous + // scrolling), or update_topline() in win_update() will cause a + // scroll, the screen will be redrawn later or in win_update(). + must_redraw = 0; + } + + // May need to update w_lines[]. + if (curwin->w_lines_valid == 0 && type < UPD_NOT_VALID +#ifdef FEAT_TERMINAL + && !term_do_update_window(curwin) +#endif + ) + type = UPD_NOT_VALID; + + // Postpone the redrawing when it's not needed and when being called + // recursively. + if (!redrawing() || updating_screen) + { + redraw_later(type); // remember type for next time + must_redraw = type; + if (type > UPD_INVERTED_ALL) + curwin->w_lines_valid = 0; // don't use w_lines[].wl_size now + return FAIL; + } + updating_screen = TRUE; + +#ifdef FEAT_PROP_POPUP + // Update popup_mask if needed. This may set w_redraw_top and w_redraw_bot + // in some windows. + may_update_popup_mask(type); +#endif + +#ifdef FEAT_SYN_HL + ++display_tick; // let syntax code know we're in a next round of + // display updating +#endif + if (no_update) + ++no_win_do_lines_ins; + + // if the screen was scrolled up when displaying a message, scroll it down + if (msg_scrolled) + { + clear_cmdline = TRUE; + if (type != UPD_CLEAR) + { + if (msg_scrolled > Rows - 5) // redrawing is faster + { + type = UPD_NOT_VALID; + redraw_as_cleared(); + } + else + { + check_for_delay(FALSE); + if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL) + == FAIL) + { + type = UPD_NOT_VALID; + redraw_as_cleared(); + } + FOR_ALL_WINDOWS(wp) + { + if (wp->w_winrow < msg_scrolled) + { + if (W_WINROW(wp) + wp->w_height > msg_scrolled + && wp->w_redr_type < UPD_REDRAW_TOP + && wp->w_lines_valid > 0 + && wp->w_topline == wp->w_lines[0].wl_lnum) + { + wp->w_upd_rows = msg_scrolled - W_WINROW(wp); + wp->w_redr_type = UPD_REDRAW_TOP; + } + else + { + wp->w_redr_type = UPD_NOT_VALID; + if (W_WINROW(wp) + wp->w_height + + wp->w_status_height <= msg_scrolled) + wp->w_redr_status = TRUE; + } + } + } + if (!no_update) + redraw_cmdline = TRUE; + redraw_tabline = TRUE; + } + } + msg_scrolled = 0; + need_wait_return = FALSE; + } + + // reset cmdline_row now (may have been changed temporarily) + compute_cmdrow(); + + // Check for changed highlighting + if (need_highlight_changed) + highlight_changed(); + + if (type == UPD_CLEAR) // first clear screen + { + screenclear(); // will reset clear_cmdline + type = UPD_NOT_VALID; + // must_redraw may be set indirectly, avoid another redraw later + must_redraw = 0; + } + + if (clear_cmdline) // going to clear cmdline (done below) + check_for_delay(FALSE); + +#ifdef FEAT_LINEBREAK + // Force redraw when width of 'number' or 'relativenumber' column + // changes. + if (curwin->w_redr_type < UPD_NOT_VALID + && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu) + ? number_width(curwin) : 0)) + curwin->w_redr_type = UPD_NOT_VALID; +#endif + + // Only start redrawing if there is really something to do. + if (type == UPD_INVERTED) + update_curswant(); + if (curwin->w_redr_type < type + && !((type == UPD_VALID + && curwin->w_lines[0].wl_valid +#ifdef FEAT_DIFF + && curwin->w_topfill == curwin->w_old_topfill + && curwin->w_botfill == curwin->w_old_botfill +#endif + && curwin->w_topline == curwin->w_lines[0].wl_lnum) + || (type == UPD_INVERTED + && VIsual_active + && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum + && curwin->w_old_visual_mode == VIsual_mode + && (curwin->w_valid & VALID_VIRTCOL) + && curwin->w_old_curswant == curwin->w_curswant) + )) + curwin->w_redr_type = type; + + // Redraw the tab pages line if needed. + if (redraw_tabline || type >= UPD_NOT_VALID) + draw_tabline(); + +#ifdef FEAT_SYN_HL + // Correct stored syntax highlighting info for changes in each displayed + // buffer. Each buffer must only be done once. + FOR_ALL_WINDOWS(wp) + { + if (wp->w_buffer->b_mod_set) + { + win_T *wwp; + + // Check if we already did this buffer. + for (wwp = firstwin; wwp != wp; wwp = wwp->w_next) + if (wwp->w_buffer == wp->w_buffer) + break; + if (wwp == wp && syntax_present(wp)) + syn_stack_apply_changes(wp->w_buffer); + } + } +#endif + + if (pum_redraw_in_same_position()) + // Avoid flicker if the popup menu is going to be redrawn in the same + // position. + pum_will_redraw = TRUE; + + // Go from top to bottom through the windows, redrawing the ones that need + // it. +#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) + did_update_one_window = FALSE; +#endif +#ifdef FEAT_SEARCH_EXTRA + screen_search_hl.rm.regprog = NULL; +#endif + FOR_ALL_WINDOWS(wp) + { + if (wp->w_redr_type != 0) + { + cursor_off(); +#ifdef FEAT_GUI + if (!did_one) + { + did_one = TRUE; + + // Remove the cursor before starting to do anything, because + // scrolling may make it difficult to redraw the text under + // it. + // Also remove the cursor if it needs to be hidden due to an + // ongoing cursor-less sleep. + if (gui.in_use && (wp == curwin || cursor_is_sleeping())) + { + gui_cursor_col = gui.cursor_col; + gui_cursor_row = gui.cursor_row; + gui_undraw_cursor(); + did_undraw = TRUE; + } + } +#endif + win_update(wp); + } + + // redraw status line after the window to minimize cursor movement + if (wp->w_redr_status) + { + cursor_off(); + win_redr_status(wp, TRUE); // any popup menu will be redrawn below + } + } +#if defined(FEAT_SEARCH_EXTRA) + end_search_hl(); +#endif + + // May need to redraw the popup menu. + pum_will_redraw = save_pum_will_redraw; + pum_may_redraw(); + + // Reset b_mod_set flags. Going through all windows is probably faster + // than going through all buffers (there could be many buffers). + FOR_ALL_WINDOWS(wp) + wp->w_buffer->b_mod_set = FALSE; + +#ifdef FEAT_PROP_POPUP + // Display popup windows on top of the windows and command line. + update_popups(win_update); +#endif + +#ifdef FEAT_TERMINAL + FOR_ALL_WINDOWS(wp) + // If this window contains a terminal, after redrawing all windows, the + // dirty row range can be reset. + term_did_update_window(wp); +#endif + + after_updating_screen(TRUE); + + // Clear or redraw the command line. Done last, because scrolling may + // mess up the command line. + if (clear_cmdline || redraw_cmdline || redraw_mode) + showmode(); + + if (no_update) + --no_win_do_lines_ins; + + // May put up an introductory message when not editing a file + if (!did_intro) + maybe_intro_message(); + did_intro = TRUE; + +#ifdef FEAT_GUI + // Redraw the cursor and update the scrollbars when all screen updating is + // done. + if (gui.in_use) + { + if (did_undraw && !gui_mch_is_blink_off()) + { + mch_disable_flush(); + out_flush(); // required before updating the cursor + mch_enable_flush(); + + // Put the GUI position where the cursor was, gui_update_cursor() + // uses that. + gui.col = gui_cursor_col; + gui.row = gui_cursor_row; + gui.col = mb_fix_col(gui.col, gui.row); + gui_update_cursor(FALSE, FALSE); + gui_may_flush(); + screen_cur_col = gui.col; + screen_cur_row = gui.row; + } + else + out_flush(); + gui_update_scrollbars(FALSE); + } +#endif + return OK; +} + +/* + * Return the row for drawing the statusline and the ruler of window "wp". + */ + int +statusline_row(win_T *wp) +{ +#if defined(FEAT_PROP_POPUP) + // If the window is really zero height the winbar isn't displayed. + if (wp->w_frame->fr_height == wp->w_status_height && !popup_is_popup(wp)) + return wp->w_winrow; +#endif + return W_WINROW(wp) + wp->w_height; +} + +/* + * Redraw the status line of window wp. + * + * If inversion is possible we use it. Else '=' characters are used. + * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is + * displayed. + */ + void +win_redr_status(win_T *wp, int ignore_pum UNUSED) +{ + int row; + char_u *p; + int len; + int fillchar; + int attr; + int this_ru_col; + static int busy = FALSE; + + // It's possible to get here recursively when 'statusline' (indirectly) + // invokes ":redrawstatus". Simply ignore the call then. + if (busy) + return; + busy = TRUE; + + row = statusline_row(wp); + + wp->w_redr_status = FALSE; + if (wp->w_status_height == 0) + { + // no status line, can only be last window + redraw_cmdline = TRUE; + } + else if (!redrawing() + // don't update status line when popup menu is visible and may be + // drawn over it, unless it will be redrawn later + || (!ignore_pum && pum_visible())) + { + // Don't redraw right now, do it later. + wp->w_redr_status = TRUE; + } +#ifdef FEAT_STL_OPT + else if (*p_stl != NUL || *wp->w_p_stl != NUL) + { + // redraw custom status line + redraw_custom_statusline(wp); + } +#endif + else + { + fillchar = fillchar_status(&attr, wp); + + get_trans_bufname(wp->w_buffer); + p = NameBuff; + len = (int)STRLEN(p); + + if ((bt_help(wp->w_buffer) +#ifdef FEAT_QUICKFIX + || wp->w_p_pvw +#endif + || bufIsChanged(wp->w_buffer) + || wp->w_buffer->b_p_ro) + && len < MAXPATHL - 1) + *(p + len++) = ' '; + if (bt_help(wp->w_buffer)) + { + vim_snprintf((char *)p + len, MAXPATHL - len, "%s", _("[Help]")); + len += (int)STRLEN(p + len); + } +#ifdef FEAT_QUICKFIX + if (wp->w_p_pvw) + { + vim_snprintf((char *)p + len, MAXPATHL - len, "%s", _("[Preview]")); + len += (int)STRLEN(p + len); + } +#endif + if (bufIsChanged(wp->w_buffer) && !bt_terminal(wp->w_buffer)) + { + vim_snprintf((char *)p + len, MAXPATHL - len, "%s", "[+]"); + len += (int)STRLEN(p + len); + } + if (wp->w_buffer->b_p_ro) + { + vim_snprintf((char *)p + len, MAXPATHL - len, "%s", _("[RO]")); + len += (int)STRLEN(p + len); + } + + this_ru_col = ru_col - (Columns - wp->w_width); + if (this_ru_col < (wp->w_width + 1) / 2) + this_ru_col = (wp->w_width + 1) / 2; + if (this_ru_col <= 1) + { + p = (char_u *)"<"; // No room for file name! + len = 1; + } + else if (has_mbyte) + { + int clen = 0, i; + + // Count total number of display cells. + clen = mb_string2cells(p, -1); + + // Find first character that will fit. + // Going from start to end is much faster for DBCS. + for (i = 0; p[i] != NUL && clen >= this_ru_col - 1; + i += (*mb_ptr2len)(p + i)) + clen -= (*mb_ptr2cells)(p + i); + len = clen; + if (i > 0) + { + p = p + i - 1; + *p = '<'; + ++len; + } + + } + else if (len > this_ru_col - 1) + { + p += len - (this_ru_col - 1); + *p = '<'; + len = this_ru_col - 1; + } + + screen_puts(p, row, wp->w_wincol, attr); + screen_fill(row, row + 1, len + wp->w_wincol, + this_ru_col + wp->w_wincol, fillchar, fillchar, attr); + + if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL) + && (this_ru_col - len) > (int)(STRLEN(NameBuff) + 1)) + screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff) + - 1 + wp->w_wincol), attr); + + win_redr_ruler(wp, TRUE, ignore_pum); + + // Draw the 'showcmd' information if 'showcmdloc' == "statusline". + if (p_sc && *p_sloc == 's') + { + int width = MIN(10, this_ru_col - len - 2); + + if (width > 0) + screen_puts_len(showcmd_buf, width, row, + wp->w_wincol + this_ru_col - width - 1, attr); + } + } + + /* + * May need to draw the character below the vertical separator. + */ + if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing()) + { + if (stl_connected(wp)) + fillchar = fillchar_status(&attr, wp); + else + fillchar = fillchar_vsep(&attr, wp); + screen_putchar(fillchar, row, W_ENDCOL(wp), attr); + } + busy = FALSE; +} + +#ifdef FEAT_STL_OPT +/* + * Redraw the status line according to 'statusline' and take care of any + * errors encountered. + */ + static void +redraw_custom_statusline(win_T *wp) +{ + static int entered = FALSE; + + // When called recursively return. This can happen when the statusline + // contains an expression that triggers a redraw. + if (entered) + return; + entered = TRUE; + + win_redr_custom(wp, FALSE); + entered = FALSE; +} +#endif + +/* + * Show current status info in ruler and various other places + * If always is FALSE, only show ruler if position has changed. + */ + void +showruler(int always) +{ + if (!always && !redrawing()) + return; + if (pum_visible()) + { + // Don't redraw right now, do it later. + curwin->w_redr_status = TRUE; + return; + } +#if defined(FEAT_STL_OPT) + if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height) + redraw_custom_statusline(curwin); + else +#endif + win_redr_ruler(curwin, always, FALSE); + + if (need_maketitle +#ifdef FEAT_STL_OPT + || (p_icon && (stl_syntax & STL_IN_ICON)) + || (p_title && (stl_syntax & STL_IN_TITLE)) +#endif + ) + maketitle(); + + // Redraw the tab pages line if needed. + if (redraw_tabline) + draw_tabline(); +} + + void +win_redr_ruler(win_T *wp, int always, int ignore_pum) +{ +#define RULER_BUF_LEN 70 + char_u buffer[RULER_BUF_LEN]; + int row; + int fillchar; + int attr; + int empty_line = FALSE; + colnr_T virtcol; + int i; + size_t len; + int o; + int this_ru_col; + int off = 0; + int width; + + // If 'ruler' off don't do anything + if (!p_ru) + return; + + /* + * Check if cursor.lnum is valid, since win_redr_ruler() may be called + * after deleting lines, before cursor.lnum is corrected. + */ + if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) + return; + + // Don't draw the ruler while doing insert-completion, it might overwrite + // the (long) mode message. + if (wp == lastwin && lastwin->w_status_height == 0) + if (edit_submode != NULL) + return; + // Don't draw the ruler when the popup menu is visible, it may overlap. + // Except when the popup menu will be redrawn anyway. + if (!ignore_pum && pum_visible()) + return; + +#ifdef FEAT_STL_OPT + if (*p_ruf) + { + win_redr_custom(wp, TRUE); + return; + } +#endif + + /* + * Check if not in Insert mode and the line is empty (will show "0-1"). + */ + if ((State & MODE_INSERT) == 0 + && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL) + empty_line = TRUE; + + /* + * Only draw the ruler when something changed. + */ + validate_virtcol_win(wp); + if ( redraw_cmdline + || always + || wp->w_cursor.lnum != wp->w_ru_cursor.lnum + || wp->w_cursor.col != wp->w_ru_cursor.col + || wp->w_virtcol != wp->w_ru_virtcol + || wp->w_cursor.coladd != wp->w_ru_cursor.coladd + || wp->w_topline != wp->w_ru_topline + || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count +#ifdef FEAT_DIFF + || wp->w_topfill != wp->w_ru_topfill +#endif + || empty_line != wp->w_ru_empty) + { + cursor_off(); + if (wp->w_status_height) + { + row = statusline_row(wp); + fillchar = fillchar_status(&attr, wp); + off = wp->w_wincol; + width = wp->w_width; + } + else + { + row = Rows - 1; + fillchar = ' '; + attr = 0; + width = Columns; + off = 0; + } + + // In list mode virtcol needs to be recomputed + virtcol = wp->w_virtcol; + if (wp->w_p_list && wp->w_lcs_chars.tab1 == NUL) + { + wp->w_p_list = FALSE; + getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL); + wp->w_p_list = TRUE; + } + + /* + * Some sprintfs return the length, some return a pointer. + * To avoid portability problems we use strlen() here. + */ + vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,", + (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) + ? 0L + : (long)(wp->w_cursor.lnum)); + len = STRLEN(buffer); + col_print(buffer + len, RULER_BUF_LEN - len, + empty_line ? 0 : (int)wp->w_cursor.col + 1, + (int)virtcol + 1); + + /* + * Add a "50%" if there is room for it. + * On the last line, don't print in the last column (scrolls the + * screen up on some terminals). + */ + i = (int)STRLEN(buffer); + get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1); + o = i + vim_strsize(buffer + i + 1); + if (wp->w_status_height == 0) // can't use last char of screen + ++o; + this_ru_col = ru_col - (Columns - width); + if (this_ru_col < 0) + this_ru_col = 0; + // Never use more than half the window/screen width, leave the other + // half for the filename. + if (this_ru_col < (width + 1) / 2) + this_ru_col = (width + 1) / 2; + if (this_ru_col + o < width) + { + // need at least 3 chars left for get_rel_pos() + NUL + while (this_ru_col + o < width && RULER_BUF_LEN > i + 4) + { + if (has_mbyte) + i += (*mb_char2bytes)(fillchar, buffer + i); + else + buffer[i++] = fillchar; + ++o; + } + get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i); + } + // Truncate at window boundary. + if (has_mbyte) + { + o = 0; + for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i)) + { + o += (*mb_ptr2cells)(buffer + i); + if (this_ru_col + o > width) + { + buffer[i] = NUL; + break; + } + } + } + else if (this_ru_col + (int)STRLEN(buffer) > width) + buffer[width - this_ru_col] = NUL; + + screen_puts(buffer, row, this_ru_col + off, attr); + i = redraw_cmdline; + screen_fill(row, row + 1, + this_ru_col + off + (int)STRLEN(buffer), + (off + width), + fillchar, fillchar, attr); + // don't redraw the cmdline because of showing the ruler + redraw_cmdline = i; + wp->w_ru_cursor = wp->w_cursor; + wp->w_ru_virtcol = wp->w_virtcol; + wp->w_ru_empty = empty_line; + wp->w_ru_topline = wp->w_topline; + wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count; +#ifdef FEAT_DIFF + wp->w_ru_topfill = wp->w_topfill; +#endif + } +} + +/* + * To be called when "updating_screen" was set before and now the postponed + * side effects may take place. + */ + void +after_updating_screen(int may_resize_shell UNUSED) +{ + updating_screen = FALSE; +#ifdef FEAT_GUI + if (may_resize_shell) + gui_may_resize_shell(); +#endif +#ifdef FEAT_TERMINAL + term_check_channel_closed_recently(); +#endif + +#ifdef HAVE_DROP_FILE + // If handle_drop() was called while updating_screen was TRUE need to + // handle the drop now. + handle_any_postponed_drop(); +#endif +} + +/* + * Update all windows that are editing the current buffer. + */ + void +update_curbuf(int type) +{ + redraw_curbuf_later(type); + update_screen(type); +} + +#if defined(FEAT_MENU) || defined(FEAT_FOLDING) +/* + * Copy "text" to ScreenLines using "attr". + * Returns the next screen column. + */ + static int +text_to_screenline(win_T *wp, char_u *text, int col) +{ + int off = (int)(current_ScreenLine - ScreenLines); + + if (has_mbyte) + { + int cells; + int u8c, u8cc[MAX_MCO]; + int i; + int idx; + int c_len; + char_u *p; +# ifdef FEAT_ARABIC + int prev_c = 0; // previous Arabic character + int prev_c1 = 0; // first composing char for prev_c +# endif + +# ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + idx = off; + else +# endif + idx = off + col; + + // Store multibyte characters in ScreenLines[] et al. correctly. + for (p = text; *p != NUL; ) + { + cells = (*mb_ptr2cells)(p); + c_len = (*mb_ptr2len)(p); + if (col + cells > wp->w_width +# ifdef FEAT_RIGHTLEFT + - (wp->w_p_rl ? col : 0) +# endif + ) + break; + ScreenLines[idx] = *p; + if (enc_utf8) + { + u8c = utfc_ptr2char(p, u8cc); + if (*p < 0x80 && u8cc[0] == 0) + { + ScreenLinesUC[idx] = 0; +#ifdef FEAT_ARABIC + prev_c = u8c; +#endif + } + else + { +#ifdef FEAT_ARABIC + if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) + { + // Do Arabic shaping. + int pc, pc1, nc; + int pcc[MAX_MCO]; + int firstbyte = *p; + + // The idea of what is the previous and next + // character depends on 'rightleft'. + if (wp->w_p_rl) + { + pc = prev_c; + pc1 = prev_c1; + nc = utf_ptr2char(p + c_len); + prev_c1 = u8cc[0]; + } + else + { + pc = utfc_ptr2char(p + c_len, pcc); + nc = prev_c; + pc1 = pcc[0]; + } + prev_c = u8c; + + u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], + pc, pc1, nc); + ScreenLines[idx] = firstbyte; + } + else + prev_c = u8c; +#endif + // Non-BMP character: display as ? or fullwidth ?. + ScreenLinesUC[idx] = u8c; + for (i = 0; i < Screen_mco; ++i) + { + ScreenLinesC[i][idx] = u8cc[i]; + if (u8cc[i] == 0) + break; + } + } + if (cells > 1) + ScreenLines[idx + 1] = 0; + } + else if (enc_dbcs == DBCS_JPNU && *p == 0x8e) + // double-byte single width character + ScreenLines2[idx] = p[1]; + else if (cells > 1) + // double-width character + ScreenLines[idx + 1] = p[1]; + col += cells; + idx += cells; + p += c_len; + } + } + else + { + int len = (int)STRLEN(text); + + if (len > wp->w_width - col) + len = wp->w_width - col; + if (len > 0) + { +#ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + mch_memmove(current_ScreenLine, text, len); + else +#endif + mch_memmove(current_ScreenLine + col, text, len); + col += len; + } + } + return col; +} +#endif + +#ifdef FEAT_MENU +/* + * Draw the window toolbar. + */ + static void +redraw_win_toolbar(win_T *wp) +{ + vimmenu_T *menu; + int item_idx = 0; + int item_count = 0; + int col = 0; + int next_col; + int off = (int)(current_ScreenLine - ScreenLines); + int fill_attr = syn_name2attr((char_u *)"ToolbarLine"); + int button_attr = syn_name2attr((char_u *)"ToolbarButton"); + + vim_free(wp->w_winbar_items); + FOR_ALL_CHILD_MENUS(wp->w_winbar, menu) + ++item_count; + wp->w_winbar_items = ALLOC_CLEAR_MULT(winbar_item_T, item_count + 1); + + // TODO: use fewer spaces if there is not enough room + for (menu = wp->w_winbar->children; + menu != NULL && col < wp->w_width; menu = menu->next) + { + space_to_screenline(off + col, fill_attr); + if (++col >= wp->w_width) + break; + if (col > 1) + { + space_to_screenline(off + col, fill_attr); + if (++col >= wp->w_width) + break; + } + + wp->w_winbar_items[item_idx].wb_startcol = col; + space_to_screenline(off + col, button_attr); + if (++col >= wp->w_width) + break; + + next_col = text_to_screenline(wp, menu->name, col); + while (col < next_col) + { + ScreenAttrs[off + col] = button_attr; + ++col; + } + wp->w_winbar_items[item_idx].wb_endcol = col; + wp->w_winbar_items[item_idx].wb_menu = menu; + ++item_idx; + + if (col >= wp->w_width) + break; + space_to_screenline(off + col, button_attr); + ++col; + } + while (col < wp->w_width) + { + space_to_screenline(off + col, fill_attr); + ++col; + } + wp->w_winbar_items[item_idx].wb_menu = NULL; // end marker + + screen_line(wp, wp->w_winrow, wp->w_wincol, wp->w_width, wp->w_width, 0); +} +#endif + +#if defined(FEAT_FOLDING) || defined(PROTO) +/* + * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr". + */ + static void +copy_text_attr( + int off, + char_u *buf, + int len, + int attr) +{ + int i; + + mch_memmove(ScreenLines + off, buf, (size_t)len); + if (enc_utf8) + vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len); + for (i = 0; i < len; ++i) + ScreenAttrs[off + i] = attr; +} + +/* + * Display one folded line. + */ + static void +fold_line( + win_T *wp, + long fold_count, + foldinfo_T *foldinfo, + linenr_T lnum, + int row) +{ + // Max value of 'foldcolumn' is 12 and maximum number of bytes in a + // multi-byte character is MAX_MCO. + char_u buf[MAX_MCO * 12 + 1]; + pos_T *top, *bot; + linenr_T lnume = lnum + fold_count - 1; + int len; + char_u *text; + int fdc; + int col; + int txtcol; + int off = (int)(current_ScreenLine - ScreenLines); + int ri; + + // Build the fold line: + // 1. Add the cmdwin_type for the command-line window + // 2. Add the 'foldcolumn' + // 3. Add the 'number' or 'relativenumber' column + // 4. Compose the text + // 5. Add the text + // 6. set highlighting for the Visual area an other text + col = 0; + + // 1. Add the cmdwin_type for the command-line window + // Ignores 'rightleft', this window is never right-left. + if (cmdwin_type != 0 && wp == curwin) + { + ScreenLines[off] = cmdwin_type; + ScreenAttrs[off] = HL_ATTR(HLF_AT); + if (enc_utf8) + ScreenLinesUC[off] = 0; + ++col; + } + +#ifdef FEAT_RIGHTLEFT +# define RL_MEMSET(p, v, l) \ + do { \ + if (wp->w_p_rl) \ + for (ri = 0; ri < (l); ++ri) \ + ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \ + else \ + for (ri = 0; ri < (l); ++ri) \ + ScreenAttrs[off + (p) + ri] = v; \ + } while (0) +#else +# define RL_MEMSET(p, v, l) \ + do { \ + for (ri = 0; ri < l; ++ri) \ + ScreenAttrs[off + (p) + ri] = v; \ + } while (0) +#endif + + // 2. Add the 'foldcolumn' + // Reduce the width when there is not enough space. + fdc = compute_foldcolumn(wp, col); + if (fdc > 0) + { + char_u *p; + int i; + int idx; + + fill_foldcolumn(buf, wp, TRUE, lnum); + p = buf; + for (i = 0; i < fdc; i++) + { + int ch; + + if (has_mbyte) + ch = mb_ptr2char_adv(&p); + else + ch = *p++; +#ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + idx = off + wp->w_width - i - 1 - col; + else +#endif + idx = off + col + i; + if (enc_utf8) + { + if (ch >= 0x80) + { + ScreenLinesUC[idx] = ch; + ScreenLinesC[0][idx] = 0; + ScreenLines[idx] = 0x80; + } + else + { + ScreenLines[idx] = ch; + ScreenLinesUC[idx] = 0; + } + } + else + ScreenLines[idx] = ch; + } + + RL_MEMSET(col, HL_ATTR(HLF_FC), fdc); + col += fdc; + } + + // Set all attributes of the 'number' or 'relativenumber' column and the + // text + RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col); + +#ifdef FEAT_SIGNS + // If signs are being displayed, add two spaces. + if (signcolumn_on(wp)) + { + len = wp->w_width - col; + if (len > 0) + { + if (len > 2) + len = 2; +# ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + // the line number isn't reversed + copy_text_attr(off + wp->w_width - len - col, + (char_u *)" ", len, HL_ATTR(HLF_FL)); + else +# endif + copy_text_attr(off + col, (char_u *)" ", len, HL_ATTR(HLF_FL)); + col += len; + } + } +#endif + + // 3. Add the 'number' or 'relativenumber' column + if (wp->w_p_nu || wp->w_p_rnu) + { + len = wp->w_width - col; + if (len > 0) + { + int w = number_width(wp); + long num; + char *fmt = "%*ld "; + + if (len > w + 1) + len = w + 1; + + if (wp->w_p_nu && !wp->w_p_rnu) + // 'number' + 'norelativenumber' + num = (long)lnum; + else + { + // 'relativenumber', don't use negative numbers + num = labs((long)get_cursor_rel_lnum(wp, lnum)); + if (num == 0 && wp->w_p_nu && wp->w_p_rnu) + { + // 'number' + 'relativenumber': cursor line shows absolute + // line number + num = lnum; + fmt = "%-*ld "; + } + } + + sprintf((char *)buf, fmt, w, num); +#ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + // the line number isn't reversed + copy_text_attr(off + wp->w_width - len - col, buf, len, + HL_ATTR(HLF_FL)); + else +#endif + copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL)); + col += len; + } + } + + // 4. Compose the folded-line string with 'foldtext', if set. + text = get_foldtext(wp, lnum, lnume, foldinfo, buf); + + txtcol = col; // remember where text starts + + // 5. move the text to current_ScreenLine. Fill up with "fold" from + // 'fillchars'. + // Right-left text is put in columns 0 - number-col, normal text is put + // in columns number-col - window-width. + col = text_to_screenline(wp, text, col); + + // Fill the rest of the line with the fold filler +#ifdef FEAT_RIGHTLEFT + if (wp->w_p_rl) + col -= txtcol; +#endif + while (col < wp->w_width +#ifdef FEAT_RIGHTLEFT + - (wp->w_p_rl ? txtcol : 0) +#endif + ) + { + int c = wp->w_fill_chars.fold; + + if (enc_utf8) + { + if (c >= 0x80) + { + ScreenLinesUC[off + col] = c; + ScreenLinesC[0][off + col] = 0; + ScreenLines[off + col] = 0x80; // avoid storing zero + } + else + { + ScreenLinesUC[off + col] = 0; + ScreenLines[off + col] = c; + } + col++; + } + else + ScreenLines[off + col++] = c; + } + + if (text != buf) + vim_free(text); + + // 6. set highlighting for the Visual area an other text. + // If all folded lines are in the Visual area, highlight the line. + if (VIsual_active && wp->w_buffer == curwin->w_buffer) + { + if (LTOREQ_POS(curwin->w_cursor, VIsual)) + { + // Visual is after curwin->w_cursor + top = &curwin->w_cursor; + bot = &VIsual; + } + else + { + // Visual is before curwin->w_cursor + top = &VIsual; + bot = &curwin->w_cursor; + } + if (lnum >= top->lnum + && lnume <= bot->lnum + && (VIsual_mode != 'v' + || ((lnum > top->lnum + || (lnum == top->lnum + && top->col == 0)) + && (lnume < bot->lnum + || (lnume == bot->lnum + && (bot->col - (*p_sel == 'e')) + >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE))))))) + { + if (VIsual_mode == Ctrl_V) + { + // Visual block mode: highlight the chars part of the block + if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width) + { + if (wp->w_old_cursor_lcol != MAXCOL + && wp->w_old_cursor_lcol + txtcol + < (colnr_T)wp->w_width) + len = wp->w_old_cursor_lcol; + else + len = wp->w_width - txtcol; + RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V), + len - (int)wp->w_old_cursor_fcol); + } + } + else + { + // Set all attributes of the text + RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol); + } + } + } + +#ifdef FEAT_SYN_HL + // Show colorcolumn in the fold line, but let cursorcolumn override it. + if (wp->w_p_cc_cols) + { + int i = 0; + int j = wp->w_p_cc_cols[i]; + int old_txtcol = txtcol; + + while (j > -1) + { + txtcol += j; + if (wp->w_p_wrap) + txtcol -= wp->w_skipcol; + else + txtcol -= wp->w_leftcol; + if (txtcol >= 0 && txtcol < wp->w_width) + ScreenAttrs[off + txtcol] = hl_combine_attr( + ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC)); + txtcol = old_txtcol; + j = wp->w_p_cc_cols[++i]; + } + } + + // Show 'cursorcolumn' in the fold line. + if (wp->w_p_cuc) + { + txtcol += wp->w_virtcol; + if (wp->w_p_wrap) + txtcol -= wp->w_skipcol; + else + txtcol -= wp->w_leftcol; + if (txtcol >= 0 && txtcol < wp->w_width) + ScreenAttrs[off + txtcol] = hl_combine_attr( + ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC)); + } +#endif + + screen_line(wp, row + W_WINROW(wp), wp->w_wincol, + wp->w_width, wp->w_width, 0); + + // Update w_cline_height and w_cline_folded if the cursor line was + // updated (saves a call to plines() later). + if (wp == curwin + && lnum <= curwin->w_cursor.lnum + && lnume >= curwin->w_cursor.lnum) + { + curwin->w_cline_row = row; + curwin->w_cline_height = 1; + curwin->w_cline_folded = TRUE; + curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); + } + +# ifdef FEAT_CONCEAL + // When the line was not folded w_wrow may have been set, recompute it. + if (wp == curwin + && wp->w_cursor.lnum >= lnum + && wp->w_cursor.lnum <= lnume + && conceal_cursor_line(wp)) + curs_columns(TRUE); +# endif +} +#endif + +/* + * Update a single window. + * + * This may cause the windows below it also to be redrawn (when clearing the + * screen or scrolling lines). + * + * How the window is redrawn depends on wp->w_redr_type. Each type also + * implies the one below it. + * UPD_NOT_VALID redraw the whole window + * UPD_SOME_VALID redraw the whole window but do scroll when possible + * UPD_REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like + * UPD_VALID + * UPD_INVERTED redraw the changed part of the Visual area + * UPD_INVERTED_ALL redraw the whole Visual area + * UPD_VALID 1. scroll up/down to adjust for a changed w_topline + * 2. update lines at the top when scrolled down + * 3. redraw changed text: + * - if wp->w_buffer->b_mod_set set, update lines between + * b_mod_top and b_mod_bot. + * - if wp->w_redraw_top non-zero, redraw lines between + * wp->w_redraw_top and wp->w_redr_bot. + * - continue redrawing when syntax status is invalid. + * 4. if scrolled up, update lines at the bottom. + * This results in three areas that may need updating: + * top: from first row to top_end (when scrolled down) + * mid: from mid_start to mid_end (update inversion or changed text) + * bot: from bot_start to last row (when scrolled up) + */ + static void +win_update(win_T *wp) +{ + buf_T *buf = wp->w_buffer; + int type; + int top_end = 0; // Below last row of the top area that needs + // updating. 0 when no top area updating. + int mid_start = 999;// first row of the mid area that needs + // updating. 999 when no mid area updating. + int mid_end = 0; // Below last row of the mid area that needs + // updating. 0 when no mid area updating. + int bot_start = 999;// first row of the bot area that needs + // updating. 999 when no bot area updating + int scrolled_down = FALSE; // TRUE when scrolled down when + // w_topline got smaller a bit +#ifdef FEAT_SEARCH_EXTRA + int top_to_mod = FALSE; // redraw above mod_top +#endif + + int row; // current window row to display + linenr_T lnum; // current buffer lnum to display + int idx; // current index in w_lines[] + int srow; // starting row of the current line + + int eof = FALSE; // if TRUE, we hit the end of the file + int didline = FALSE; // if TRUE, we finished the last line + int i; + long j; + static int recursive = FALSE; // being called recursively + linenr_T old_botline = wp->w_botline; +#ifdef FEAT_CONCEAL + int old_wrow = wp->w_wrow; + int old_wcol = wp->w_wcol; +#endif +#ifdef FEAT_FOLDING + long fold_count; +#endif +#ifdef FEAT_SYN_HL + // remember what happened to the previous line, to know if + // check_visual_highlight() can be used +# define DID_NONE 1 // didn't update a line +# define DID_LINE 2 // updated a normal line +# define DID_FOLD 3 // updated a folded line + int did_update = DID_NONE; + linenr_T syntax_last_parsed = 0; // last parsed text line +#endif + linenr_T mod_top = 0; + linenr_T mod_bot = 0; +#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) + int save_got_int; +#endif + +#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) + // This needs to be done only for the first window when update_screen() is + // called. + if (!did_update_one_window) + { + did_update_one_window = TRUE; +# ifdef FEAT_SEARCH_EXTRA + start_search_hl(); +# endif +# ifdef FEAT_CLIPBOARD + // When Visual area changed, may have to update selection. + if (clip_star.available && clip_isautosel_star()) + clip_update_selection(&clip_star); + if (clip_plus.available && clip_isautosel_plus()) + clip_update_selection(&clip_plus); +# endif + } +#endif + + type = wp->w_redr_type; + + if (type == UPD_NOT_VALID) + { + wp->w_redr_status = TRUE; + wp->w_lines_valid = 0; + } + + // Window frame is zero-height: nothing to draw. + if (wp->w_height + WINBAR_HEIGHT(wp) == 0 + || (wp->w_frame->fr_height == wp->w_status_height +#if defined(FEAT_PROP_POPUP) + && !popup_is_popup(wp) +#endif + )) + { + wp->w_redr_type = 0; + return; + } + + // Window is zero-width: Only need to draw the separator. + if (wp->w_width == 0) + { + // draw the vertical separator right of this window + draw_vsep_win(wp, 0); + wp->w_redr_type = 0; + return; + } + +#ifdef FEAT_TERMINAL + // If this window contains a terminal, redraw works completely differently. + if (term_do_update_window(wp)) + { + term_update_window(wp); +# ifdef FEAT_MENU + // Draw the window toolbar, if there is one. + if (winbar_height(wp) > 0) + redraw_win_toolbar(wp); +# endif + wp->w_redr_type = 0; + return; + } +#endif + +#ifdef FEAT_SEARCH_EXTRA + init_search_hl(wp, &screen_search_hl); +#endif + + // Make sure skipcol is valid, it depends on various options and the window + // width. + if (wp->w_skipcol > 0) + { + int w = 0; + int width1 = wp->w_width - win_col_off(wp); + int width2 = width1 + win_col_off2(wp); + int add = width1; + + while (w < wp->w_skipcol) + { + if (w > 0) + add = width2; + w += add; + } + if (w != wp->w_skipcol) + // always round down, the higher value may not be valid + wp->w_skipcol = w - add; + } + +#ifdef FEAT_LINEBREAK + // Force redraw when width of 'number' or 'relativenumber' column + // changes. + i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0; + if (wp->w_nrwidth != i) + { + type = UPD_NOT_VALID; + wp->w_nrwidth = i; + } + else +#endif + + if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0) + { + // When there are both inserted/deleted lines and specific lines to be + // redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw + // everything (only happens when redrawing is off for while). + type = UPD_NOT_VALID; + } + else + { + // Set mod_top to the first line that needs displaying because of + // changes. Set mod_bot to the first line after the changes. + mod_top = wp->w_redraw_top; + if (wp->w_redraw_bot != 0) + mod_bot = wp->w_redraw_bot + 1; + else + mod_bot = 0; + if (buf->b_mod_set) + { + if (mod_top == 0 || mod_top > buf->b_mod_top) + { + mod_top = buf->b_mod_top; +#ifdef FEAT_SYN_HL + // Need to redraw lines above the change that may be included + // in a pattern match. + if (syntax_present(wp)) + { + mod_top -= buf->b_s.b_syn_sync_linebreaks; + if (mod_top < 1) + mod_top = 1; + } +#endif + } + if (mod_bot == 0 || mod_bot < buf->b_mod_bot) + mod_bot = buf->b_mod_bot; + +#ifdef FEAT_SEARCH_EXTRA + // When 'hlsearch' is on and using a multi-line search pattern, a + // change in one line may make the Search highlighting in a + // previous line invalid. Simple solution: redraw all visible + // lines above the change. + // Same for a match pattern. + if (screen_search_hl.rm.regprog != NULL + && re_multiline(screen_search_hl.rm.regprog)) + top_to_mod = TRUE; + else + { + matchitem_T *cur = wp->w_match_head; + + while (cur != NULL) + { + if (cur->mit_match.regprog != NULL + && re_multiline(cur->mit_match.regprog)) + { + top_to_mod = TRUE; + break; + } + cur = cur->mit_next; + } + } +#endif + } + +#ifdef FEAT_SEARCH_EXTRA + if (search_hl_has_cursor_lnum > 0) + { + // CurSearch was used last time, need to redraw the line with it to + // avoid having two matches highlighted with CurSearch. + if (mod_top == 0 || mod_top > search_hl_has_cursor_lnum) + mod_top = search_hl_has_cursor_lnum; + if (mod_bot == 0 || mod_bot < search_hl_has_cursor_lnum + 1) + mod_bot = search_hl_has_cursor_lnum + 1; + } +#endif + +#ifdef FEAT_FOLDING + if (mod_top != 0 && hasAnyFolding(wp)) + { + linenr_T lnumt, lnumb; + + // A change in a line can cause lines above it to become folded or + // unfolded. Find the top most buffer line that may be affected. + // If the line was previously folded and displayed, get the first + // line of that fold. If the line is folded now, get the first + // folded line. Use the minimum of these two. + + // Find last valid w_lines[] entry above mod_top. Set lnumt to + // the line below it. If there is no valid entry, use w_topline. + // Find the first valid w_lines[] entry below mod_bot. Set lnumb + // to this line. If there is no valid entry, use MAXLNUM. + lnumt = wp->w_topline; + lnumb = MAXLNUM; + for (i = 0; i < wp->w_lines_valid; ++i) + if (wp->w_lines[i].wl_valid) + { + if (wp->w_lines[i].wl_lastlnum < mod_top) + lnumt = wp->w_lines[i].wl_lastlnum + 1; + if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot) + { + lnumb = wp->w_lines[i].wl_lnum; + // When there is a fold column it might need updating + // in the next line ("J" just above an open fold). + if (compute_foldcolumn(wp, 0) > 0) + ++lnumb; + } + } + + (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL); + if (mod_top > lnumt) + mod_top = lnumt; + + // Now do the same for the bottom line (one above mod_bot). + --mod_bot; + (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL); + ++mod_bot; + if (mod_bot < lnumb) + mod_bot = lnumb; + } +#endif + + // When a change starts above w_topline and the end is below + // w_topline, start redrawing at w_topline. + // If the end of the change is above w_topline: do like no change was + // made, but redraw the first line to find changes in syntax. + if (mod_top != 0 && mod_top < wp->w_topline) + { + if (mod_bot > wp->w_topline) + mod_top = wp->w_topline; +#ifdef FEAT_SYN_HL + else if (syntax_present(wp)) + top_end = 1; +#endif + } + + // When line numbers are displayed need to redraw all lines below + // inserted/deleted lines. + if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu) + mod_bot = MAXLNUM; + } + wp->w_redraw_top = 0; // reset for next time + wp->w_redraw_bot = 0; +#ifdef FEAT_SEARCH_EXTRA + search_hl_has_cursor_lnum = 0; +#endif + + + // When only displaying the lines at the top, set top_end. Used when + // window has scrolled down for msg_scrolled. + if (type == UPD_REDRAW_TOP) + { + j = 0; + for (i = 0; i < wp->w_lines_valid; ++i) + { + j += wp->w_lines[i].wl_size; + if (j >= wp->w_upd_rows) + { + top_end = j; + break; + } + } + if (top_end == 0) + // not found (cannot happen?): redraw everything + type = UPD_NOT_VALID; + else + // top area defined, the rest is UPD_VALID + type = UPD_VALID; + } + + // Trick: we want to avoid clearing the screen twice. screenclear() will + // set "screen_cleared" to TRUE. The special value MAYBE (which is still + // non-zero and thus not FALSE) will indicate that screenclear() was not + // called. + if (screen_cleared) + screen_cleared = MAYBE; + + // If there are no changes on the screen that require a complete redraw, + // handle three cases: + // 1: we are off the top of the screen by a few lines: scroll down + // 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up + // 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in + // w_lines[] that needs updating. + if ((type == UPD_VALID || type == UPD_SOME_VALID + || type == UPD_INVERTED || type == UPD_INVERTED_ALL) +#ifdef FEAT_DIFF + && !wp->w_botfill && !wp->w_old_botfill +#endif + ) + { + if (mod_top != 0 + && wp->w_topline == mod_top + && (!wp->w_lines[0].wl_valid + || wp->w_topline == wp->w_lines[0].wl_lnum)) + { + // w_topline is the first changed line and window is not scrolled, + // the scrolling from changed lines will be done further down. + } + else if (wp->w_lines[0].wl_valid + && (wp->w_topline < wp->w_lines[0].wl_lnum +#ifdef FEAT_DIFF + || (wp->w_topline == wp->w_lines[0].wl_lnum + && wp->w_topfill > wp->w_old_topfill) +#endif + )) + { + // New topline is above old topline: May scroll down. +#ifdef FEAT_FOLDING + if (hasAnyFolding(wp)) + { + linenr_T ln; + + // count the number of lines we are off, counting a sequence + // of folded lines as one + j = 0; + for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln) + { + ++j; + if (j >= wp->w_height - 2) + break; + (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL); + } + } + else +#endif + j = wp->w_lines[0].wl_lnum - wp->w_topline; + if (j < wp->w_height - 2) // not too far off + { + i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1); +#ifdef FEAT_DIFF + // insert extra lines for previously invisible filler lines + if (wp->w_lines[0].wl_lnum != wp->w_topline) + i += diff_check_fill(wp, wp->w_lines[0].wl_lnum) + - wp->w_old_topfill; +#endif + if (i < wp->w_height - 2) // less than a screen off + { + // Try to insert the correct number of lines. + // If not the last window, delete the lines at the bottom. + // win_ins_lines may fail when the terminal can't do it. + if (i > 0) + check_for_delay(FALSE); + if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK) + { + if (wp->w_lines_valid != 0) + { + // Need to update rows that are new, stop at the + // first one that scrolled down. + top_end = i; + scrolled_down = TRUE; + + // Move the entries that were scrolled, disable + // the entries for the lines to be redrawn. + if ((wp->w_lines_valid += j) > wp->w_height) + wp->w_lines_valid = wp->w_height; + for (idx = wp->w_lines_valid; idx - j >= 0; idx--) + wp->w_lines[idx] = wp->w_lines[idx - j]; + while (idx >= 0) + wp->w_lines[idx--].wl_valid = FALSE; + } + } + else + mid_start = 0; // redraw all lines + } + else + mid_start = 0; // redraw all lines + } + else + mid_start = 0; // redraw all lines + } + else + { + // New topline is at or below old topline: May scroll up. + // When topline didn't change, find first entry in w_lines[] that + // needs updating. + + // Try to find wp->w_topline in wp->w_lines[].wl_lnum. The check + // for "Rows" is in case "wl_size" is incorrect somehow. + j = -1; + row = 0; + for (i = 0; i < wp->w_lines_valid && i < Rows; i++) + { + if (wp->w_lines[i].wl_valid + && wp->w_lines[i].wl_lnum == wp->w_topline) + { + j = i; + break; + } + row += wp->w_lines[i].wl_size; + } + if (j == -1) + { + // if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all + // lines + mid_start = 0; + } + else + { + // Try to delete the correct number of lines. + // wp->w_topline is at wp->w_lines[i].wl_lnum. +#ifdef FEAT_DIFF + // If the topline didn't change, delete old filler lines, + // otherwise delete filler lines of the new topline... + if (wp->w_lines[0].wl_lnum == wp->w_topline) + row += wp->w_old_topfill; + else + row += diff_check_fill(wp, wp->w_topline); + // ... but don't delete new filler lines. + row -= wp->w_topfill; +#endif + if (row > Rows) // just in case + row = Rows; + if (row > 0) + { + check_for_delay(FALSE); + if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0) + == OK) + bot_start = wp->w_height - row; + else + mid_start = 0; // redraw all lines + } + if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0) + { + // Skip the lines (below the deleted lines) that are still + // valid and don't need redrawing. Copy their info + // upwards, to compensate for the deleted lines. Set + // bot_start to the first row that needs redrawing. + bot_start = 0; + idx = 0; + for (;;) + { + wp->w_lines[idx] = wp->w_lines[j]; + // stop at line that didn't fit, unless it is still + // valid (no lines deleted) + if (row > 0 && bot_start + row + + (int)wp->w_lines[j].wl_size > wp->w_height) + { + wp->w_lines_valid = idx + 1; + break; + } + bot_start += wp->w_lines[idx++].wl_size; + + // stop at the last valid entry in w_lines[].wl_size + if (++j >= wp->w_lines_valid) + { + wp->w_lines_valid = idx; + break; + } + } +#ifdef FEAT_DIFF + // Correct the first entry for filler lines at the top + // when it won't get updated below. + if (wp->w_p_diff && bot_start > 0) + wp->w_lines[0].wl_size = + plines_win_nofill(wp, wp->w_topline, TRUE) + + wp->w_topfill; +#endif + } + } + } + + // When starting redraw in the first line, redraw all lines. + if (mid_start == 0) + mid_end = wp->w_height; + + // When win_del_lines() or win_ins_lines() caused the screen to be + // cleared (only happens for the first window) or when screenclear() + // was called directly above, "must_redraw" will have been set to + // UPD_NOT_VALID, need to reset it here to avoid redrawing twice. + if (screen_cleared == TRUE) + must_redraw = 0; + } + else + { + // Not UPD_VALID or UPD_INVERTED: redraw all lines. + mid_start = 0; + mid_end = wp->w_height; + } + + if (type == UPD_SOME_VALID) + { + // UPD_SOME_VALID: redraw all lines. + mid_start = 0; + mid_end = wp->w_height; + type = UPD_NOT_VALID; + } + + // check if we are updating or removing the inverted part + if ((VIsual_active && buf == curwin->w_buffer) + || (wp->w_old_cursor_lnum != 0 && type != UPD_NOT_VALID)) + { + linenr_T from, to; + + if (VIsual_active) + { + if (VIsual_mode != wp->w_old_visual_mode + || type == UPD_INVERTED_ALL) + { + // If the type of Visual selection changed, redraw the whole + // selection. Also when the ownership of the X selection is + // gained or lost. + if (curwin->w_cursor.lnum < VIsual.lnum) + { + from = curwin->w_cursor.lnum; + to = VIsual.lnum; + } + else + { + from = VIsual.lnum; + to = curwin->w_cursor.lnum; + } + // redraw more when the cursor moved as well + if (wp->w_old_cursor_lnum < from) + from = wp->w_old_cursor_lnum; + if (wp->w_old_cursor_lnum > to) + to = wp->w_old_cursor_lnum; + if (wp->w_old_visual_lnum < from) + from = wp->w_old_visual_lnum; + if (wp->w_old_visual_lnum > to) + to = wp->w_old_visual_lnum; + } + else + { + // Find the line numbers that need to be updated: The lines + // between the old cursor position and the current cursor + // position. Also check if the Visual position changed. + if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum) + { + from = curwin->w_cursor.lnum; + to = wp->w_old_cursor_lnum; + } + else + { + from = wp->w_old_cursor_lnum; + to = curwin->w_cursor.lnum; + if (from == 0) // Visual mode just started + from = to; + } + + if (VIsual.lnum != wp->w_old_visual_lnum + || VIsual.col != wp->w_old_visual_col) + { + if (wp->w_old_visual_lnum < from + && wp->w_old_visual_lnum != 0) + from = wp->w_old_visual_lnum; + if (wp->w_old_visual_lnum > to) + to = wp->w_old_visual_lnum; + if (VIsual.lnum < from) + from = VIsual.lnum; + if (VIsual.lnum > to) + to = VIsual.lnum; + } + } + + // If in block mode and changed column or curwin->w_curswant: + // update all lines. + // First compute the actual start and end column. + if (VIsual_mode == Ctrl_V) + { + colnr_T fromc, toc; +#if defined(FEAT_LINEBREAK) + int save_ve_flags = curwin->w_ve_flags; + + if (curwin->w_p_lbr) + curwin->w_ve_flags = VE_ALL; +#endif + getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc); + ++toc; +#if defined(FEAT_LINEBREAK) + curwin->w_ve_flags = save_ve_flags; +#endif + // Highlight to the end of the line, unless 'virtualedit' has + // "block". + if (curwin->w_curswant == MAXCOL) + { + if (get_ve_flags() & VE_BLOCK) + { + pos_T pos; + int cursor_above = + curwin->w_cursor.lnum < VIsual.lnum; + + // Need to find the longest line. + toc = 0; + pos.coladd = 0; + for (pos.lnum = curwin->w_cursor.lnum; cursor_above + ? pos.lnum <= VIsual.lnum + : pos.lnum >= VIsual.lnum; + pos.lnum += cursor_above ? 1 : -1) + { + colnr_T t; + + pos.col = (int)STRLEN(ml_get_buf(wp->w_buffer, + pos.lnum, FALSE)); + getvvcol(wp, &pos, NULL, NULL, &t); + if (toc < t) + toc = t; + } + ++toc; + } + else + toc = MAXCOL; + } + + if (fromc != wp->w_old_cursor_fcol + || toc != wp->w_old_cursor_lcol) + { + if (from > VIsual.lnum) + from = VIsual.lnum; + if (to < VIsual.lnum) + to = VIsual.lnum; + } + wp->w_old_cursor_fcol = fromc; + wp->w_old_cursor_lcol = toc; + } + } + else + { + // Use the line numbers of the old Visual area. + if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum) + { + from = wp->w_old_cursor_lnum; + to = wp->w_old_visual_lnum; + } + else + { + from = wp->w_old_visual_lnum; + to = wp->w_old_cursor_lnum; + } + } + + // There is no need to update lines above the top of the window. + if (from < wp->w_topline) + from = wp->w_topline; + + // If we know the value of w_botline, use it to restrict the update to + // the lines that are visible in the window. + if (wp->w_valid & VALID_BOTLINE) + { + if (from >= wp->w_botline) + from = wp->w_botline - 1; + if (to >= wp->w_botline) + to = wp->w_botline - 1; + } + + // Find the minimal part to be updated. + // Watch out for scrolling that made entries in w_lines[] invalid. + // E.g., CTRL-U makes the first half of w_lines[] invalid and sets + // top_end; need to redraw from top_end to the "to" line. + // A middle mouse click with a Visual selection may change the text + // above the Visual area and reset wl_valid, do count these for + // mid_end (in srow). + if (mid_start > 0) + { + lnum = wp->w_topline; + idx = 0; + srow = 0; + if (scrolled_down) + mid_start = top_end; + else + mid_start = 0; + while (lnum < from && idx < wp->w_lines_valid) // find start + { + if (wp->w_lines[idx].wl_valid) + mid_start += wp->w_lines[idx].wl_size; + else if (!scrolled_down) + srow += wp->w_lines[idx].wl_size; + ++idx; +# ifdef FEAT_FOLDING + if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid) + lnum = wp->w_lines[idx].wl_lnum; + else +# endif + ++lnum; + } + srow += mid_start; + mid_end = wp->w_height; + for ( ; idx < wp->w_lines_valid; ++idx) // find end + { + if (wp->w_lines[idx].wl_valid + && wp->w_lines[idx].wl_lnum >= to + 1) + { + // Only update until first row of this line + mid_end = srow; + break; + } + srow += wp->w_lines[idx].wl_size; + } + } + } + + if (VIsual_active && buf == curwin->w_buffer) + { + wp->w_old_visual_mode = VIsual_mode; + wp->w_old_cursor_lnum = curwin->w_cursor.lnum; + wp->w_old_visual_lnum = VIsual.lnum; + wp->w_old_visual_col = VIsual.col; + wp->w_old_curswant = curwin->w_curswant; + } + else + { + wp->w_old_visual_mode = 0; + wp->w_old_cursor_lnum = 0; + wp->w_old_visual_lnum = 0; + wp->w_old_visual_col = 0; + } + +#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) + // reset got_int, otherwise regexp won't work + save_got_int = got_int; + got_int = 0; +#endif +#ifdef SYN_TIME_LIMIT + // Set the time limit to 'redrawtime'. + redrawtime_limit_set = TRUE; + init_regexp_timeout(p_rdt); +#endif +#ifdef FEAT_FOLDING + win_foldinfo.fi_level = 0; +#endif + +#ifdef FEAT_MENU + // Draw the window toolbar, if there is one. + // TODO: only when needed. + if (winbar_height(wp) > 0) + redraw_win_toolbar(wp); +#endif + + // Update all the window rows. + idx = 0; // first entry in w_lines[].wl_size + row = 0; + srow = 0; + lnum = wp->w_topline; // first line shown in window + for (;;) + { + // stop updating when reached the end of the window (check for _past_ + // the end of the window is at the end of the loop) + if (row == wp->w_height) + { + didline = TRUE; + break; + } + + // stop updating when hit the end of the file + if (lnum > buf->b_ml.ml_line_count) + { + eof = TRUE; + break; + } + + // Remember the starting row of the line that is going to be dealt + // with. It is used further down when the line doesn't fit. + srow = row; + + // Update a line when it is in an area that needs updating, when it + // has changes or w_lines[idx] is invalid. + // "bot_start" may be halfway a wrapped line after using + // win_del_lines(), check if the current line includes it. + // When syntax folding is being used, the saved syntax states will + // already have been updated, we can't see where the syntax state is + // the same again, just update until the end of the window. + if (row < top_end + || (row >= mid_start && row < mid_end) +#ifdef FEAT_SEARCH_EXTRA + || top_to_mod +#endif + || idx >= wp->w_lines_valid + || (row + wp->w_lines[idx].wl_size > bot_start) + || (mod_top != 0 + && (lnum == mod_top + || (lnum >= mod_top + && (lnum < mod_bot +#ifdef FEAT_SYN_HL + || did_update == DID_FOLD + || (did_update == DID_LINE + && syntax_present(wp) + && ( +# ifdef FEAT_FOLDING + (foldmethodIsSyntax(wp) + && hasAnyFolding(wp)) || +# endif + syntax_check_changed(lnum))) +#endif +#ifdef FEAT_SEARCH_EXTRA + // match in fixed position might need redraw + // if lines were inserted or deleted + || (wp->w_match_head != NULL + && buf->b_mod_xlines != 0) +#endif + )))) +#ifdef FEAT_SYN_HL + || (wp->w_p_cul && lnum == wp->w_cursor.lnum) + || lnum == wp->w_last_cursorline +#endif + ) + { +#ifdef FEAT_SEARCH_EXTRA + if (lnum == mod_top) + top_to_mod = FALSE; +#endif + + // When at start of changed lines: May scroll following lines + // up or down to minimize redrawing. + // Don't do this when the change continues until the end. + // Don't scroll when dollar_vcol >= 0, keep the "$". + // Don't scroll when redrawing the top, scrolled already above. + if (lnum == mod_top + && mod_bot != MAXLNUM + && !(dollar_vcol >= 0 && mod_bot == mod_top + 1) + && row >= top_end) + { + int old_rows = 0; + int new_rows = 0; + int xtra_rows; + linenr_T l; + + // Count the old number of window rows, using w_lines[], which + // should still contain the sizes for the lines as they are + // currently displayed. + for (i = idx; i < wp->w_lines_valid; ++i) + { + // Only valid lines have a meaningful wl_lnum. Invalid + // lines are part of the changed area. + if (wp->w_lines[i].wl_valid + && wp->w_lines[i].wl_lnum == mod_bot) + break; + old_rows += wp->w_lines[i].wl_size; +#ifdef FEAT_FOLDING + if (wp->w_lines[i].wl_valid + && wp->w_lines[i].wl_lastlnum + 1 == mod_bot) + { + // Must have found the last valid entry above mod_bot. + // Add following invalid entries. + ++i; + while (i < wp->w_lines_valid + && !wp->w_lines[i].wl_valid) + old_rows += wp->w_lines[i++].wl_size; + break; + } +#endif + } + + if (i >= wp->w_lines_valid) + { + // We can't find a valid line below the changed lines, + // need to redraw until the end of the window. + // Inserting/deleting lines has no use. + bot_start = 0; + } + else + { + // Able to count old number of rows: Count new window + // rows, and may insert/delete lines + j = idx; + for (l = lnum; l < mod_bot; ++l) + { +#ifdef FEAT_FOLDING + if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL)) + ++new_rows; + else +#endif + { +#ifdef FEAT_DIFF + if (l == wp->w_topline) + new_rows += plines_win_nofill(wp, l, TRUE) + + wp->w_topfill; + else +#endif + new_rows += plines_win(wp, l, TRUE); + } + ++j; + if (new_rows > wp->w_height - row - 2) + { + // it's getting too much, must redraw the rest + new_rows = 9999; + break; + } + } + xtra_rows = new_rows - old_rows; + if (xtra_rows < 0) + { + // May scroll text up. If there is not enough + // remaining text or scrolling fails, must redraw the + // rest. If scrolling works, must redraw the text + // below the scrolled text. + if (row - xtra_rows >= wp->w_height - 2) + mod_bot = MAXLNUM; + else + { + check_for_delay(FALSE); + if (win_del_lines(wp, row, + -xtra_rows, FALSE, FALSE, 0) == FAIL) + mod_bot = MAXLNUM; + else + bot_start = wp->w_height + xtra_rows; + } + } + else if (xtra_rows > 0) + { + // May scroll text down. If there is not enough + // remaining text of scrolling fails, must redraw the + // rest. + if (row + xtra_rows >= wp->w_height - 2) + mod_bot = MAXLNUM; + else + { + check_for_delay(FALSE); + if (win_ins_lines(wp, row + old_rows, + xtra_rows, FALSE, FALSE) == FAIL) + mod_bot = MAXLNUM; + else if (top_end > row + old_rows) + // Scrolled the part at the top that requires + // updating down. + top_end += xtra_rows; + } + } + + // When not updating the rest, may need to move w_lines[] + // entries. + if (mod_bot != MAXLNUM && i != j) + { + if (j < i) + { + int x = row + new_rows; + + // move entries in w_lines[] upwards + for (;;) + { + // stop at last valid entry in w_lines[] + if (i >= wp->w_lines_valid) + { + wp->w_lines_valid = j; + break; + } + wp->w_lines[j] = wp->w_lines[i]; + // stop at a line that won't fit + if (x + (int)wp->w_lines[j].wl_size + > wp->w_height) + { + wp->w_lines_valid = j + 1; + break; + } + x += wp->w_lines[j++].wl_size; + ++i; + } + if (bot_start > x) + bot_start = x; + } + else // j > i + { + // move entries in w_lines[] downwards + j -= i; + wp->w_lines_valid += j; + if (wp->w_lines_valid > wp->w_height) + wp->w_lines_valid = wp->w_height; + for (i = wp->w_lines_valid; i - j >= idx; --i) + wp->w_lines[i] = wp->w_lines[i - j]; + + // The w_lines[] entries for inserted lines are + // now invalid, but wl_size may be used above. + // Reset to zero. + while (i >= idx) + { + wp->w_lines[i].wl_size = 0; + wp->w_lines[i--].wl_valid = FALSE; + } + } + } + } + } + +#ifdef FEAT_FOLDING + // When lines are folded, display one line for all of them. + // Otherwise, display normally (can be several display lines when + // 'wrap' is on). + fold_count = foldedCount(wp, lnum, &win_foldinfo); + if (fold_count != 0) + { + fold_line(wp, fold_count, &win_foldinfo, lnum, row); + ++row; + --fold_count; + wp->w_lines[idx].wl_folded = TRUE; + wp->w_lines[idx].wl_lastlnum = lnum + fold_count; +# ifdef FEAT_SYN_HL + did_update = DID_FOLD; +# endif + } + else +#endif + if (idx < wp->w_lines_valid + && wp->w_lines[idx].wl_valid + && wp->w_lines[idx].wl_lnum == lnum + && lnum > wp->w_topline + && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) + && !WIN_IS_POPUP(wp) + && srow + wp->w_lines[idx].wl_size > wp->w_height +#ifdef FEAT_DIFF + && diff_check_fill(wp, lnum) == 0 +#endif + ) + { + // This line is not going to fit. Don't draw anything here, + // will draw "@ " lines below. + row = wp->w_height + 1; + } + else + { +#ifdef FEAT_SEARCH_EXTRA + prepare_search_hl(wp, &screen_search_hl, lnum); +#endif +#ifdef FEAT_SYN_HL + // Let the syntax stuff know we skipped a few lines. + if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum + && syntax_present(wp)) + syntax_end_parsing(wp, syntax_last_parsed + 1); +#endif + + // Display one line. + row = win_line(wp, lnum, srow, wp->w_height, + mod_top == 0, FALSE); + +#ifdef FEAT_FOLDING + wp->w_lines[idx].wl_folded = FALSE; + wp->w_lines[idx].wl_lastlnum = lnum; +#endif +#ifdef FEAT_SYN_HL + did_update = DID_LINE; + syntax_last_parsed = lnum; +#endif + } + + wp->w_lines[idx].wl_lnum = lnum; + wp->w_lines[idx].wl_valid = TRUE; + + // Past end of the window or end of the screen. Note that after + // resizing wp->w_height may be end up too big. That's a problem + // elsewhere, but prevent a crash here. + if (row > wp->w_height || row + wp->w_winrow >= Rows) + { + // we may need the size of that too long line later on + if (dollar_vcol == -1) + wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE); + ++idx; + break; + } + if (dollar_vcol == -1) + wp->w_lines[idx].wl_size = row - srow; + ++idx; +#ifdef FEAT_FOLDING + lnum += fold_count + 1; +#else + ++lnum; +#endif + } + else + { + if (wp->w_p_rnu && wp->w_last_cursor_lnum_rnu != wp->w_cursor.lnum) + { +#ifdef FEAT_FOLDING + // 'relativenumber' set and the cursor moved vertically: The + // text doesn't need to be drawn, but the number column does. + fold_count = foldedCount(wp, lnum, &win_foldinfo); + if (fold_count != 0) + fold_line(wp, fold_count, &win_foldinfo, lnum, row); + else +#endif + (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE); + } + + // This line does not need to be drawn, advance to the next one. + row += wp->w_lines[idx++].wl_size; + if (row > wp->w_height) // past end of screen + break; +#ifdef FEAT_FOLDING + lnum = wp->w_lines[idx - 1].wl_lastlnum + 1; +#else + ++lnum; +#endif +#ifdef FEAT_SYN_HL + did_update = DID_NONE; +#endif + } + + if (lnum > buf->b_ml.ml_line_count) + { + eof = TRUE; + break; + } + + // Safety check: if any of the wl_size values is wrong we might go over + // the end of w_lines[]. + if (idx >= Rows) + break; + } + + // End of loop over all window lines. + +#ifdef FEAT_SYN_HL + // Now that the window has been redrawn with the old and new cursor line, + // update w_last_cursorline. + wp->w_last_cursorline = wp->w_p_cul ? wp->w_cursor.lnum : 0; +#endif + wp->w_last_cursor_lnum_rnu = wp->w_p_rnu ? wp->w_cursor.lnum : 0; + +#ifdef FEAT_VTP + // Rewrite the character at the end of the screen line. + // See the version that was fixed. + if (use_vtp() && get_conpty_fix_type() < 1) + { + int k; + + for (k = 0; k < Rows; ++k) + if (enc_utf8) + if ((*mb_off2cells)(LineOffset[k] + Columns - 2, + LineOffset[k] + screen_Columns) > 1) + screen_draw_rectangle(k, Columns - 2, 1, 2, FALSE); + else + screen_draw_rectangle(k, Columns - 1, 1, 1, FALSE); + else + screen_char(LineOffset[k] + Columns - 1, k, Columns - 1); + } +#endif + + if (idx > wp->w_lines_valid) + wp->w_lines_valid = idx; + +#ifdef FEAT_SYN_HL + // Let the syntax stuff know we stop parsing here. + if (syntax_last_parsed != 0 && syntax_present(wp)) + syntax_end_parsing(wp, syntax_last_parsed + 1); +#endif + + // If we didn't hit the end of the file, and we didn't finish the last + // line we were working on, then the line didn't fit. + wp->w_empty_rows = 0; +#ifdef FEAT_DIFF + wp->w_filler_rows = 0; +#endif + if (!eof && !didline) + { + if (lnum == wp->w_topline) + { + // Single line that does not fit! + // Don't overwrite it, it can be edited. + wp->w_botline = lnum + 1; + } +#ifdef FEAT_DIFF + else if (diff_check_fill(wp, lnum) >= wp->w_height - srow) + { + // Window ends in filler lines. + wp->w_botline = lnum; + wp->w_filler_rows = wp->w_height - srow; + } +#endif +#ifdef FEAT_PROP_POPUP + else if (WIN_IS_POPUP(wp)) + { + // popup line that doesn't fit is left as-is + wp->w_botline = lnum; + } +#endif + else if (dy_flags & DY_TRUNCATE) // 'display' has "truncate" + { + int scr_row = W_WINROW(wp) + wp->w_height - 1; + int symbol = wp->w_fill_chars.lastline; + int charlen; + char_u fillbuf[12]; // 2 characters of 6 bytes + + charlen = mb_char2bytes(symbol, &fillbuf[0]); + mb_char2bytes(symbol, &fillbuf[charlen]); + + // Last line isn't finished: Display "@@@" in the last screen line. + screen_puts_len(fillbuf, + (wp->w_width > 2 ? 2 : wp->w_width) * charlen, + scr_row, wp->w_wincol, HL_ATTR(HLF_AT)); + screen_fill(scr_row, scr_row + 1, + (int)wp->w_wincol + 2, (int)W_ENDCOL(wp), + symbol, ' ', HL_ATTR(HLF_AT)); + set_empty_rows(wp, srow); + wp->w_botline = lnum; + } + else if (dy_flags & DY_LASTLINE) // 'display' has "lastline" + { + int start_col = (int)W_ENDCOL(wp) - 3; + int symbol = wp->w_fill_chars.lastline; + + // Last line isn't finished: Display "@@@" at the end. + screen_fill(W_WINROW(wp) + wp->w_height - 1, + W_WINROW(wp) + wp->w_height, + start_col < wp->w_wincol ? wp->w_wincol : start_col, + (int)W_ENDCOL(wp), + symbol, symbol, HL_ATTR(HLF_AT)); + set_empty_rows(wp, srow); + wp->w_botline = lnum; + } + else + { + win_draw_end(wp, wp->w_fill_chars.lastline, ' ', TRUE, + srow, wp->w_height, HLF_AT); + wp->w_botline = lnum; + } + } + else + { + draw_vsep_win(wp, row); + if (eof) // we hit the end of the file + { + wp->w_botline = buf->b_ml.ml_line_count + 1; +#ifdef FEAT_DIFF + j = diff_check_fill(wp, wp->w_botline); + if (j > 0 && !wp->w_botfill) + { + // Display filler lines at the end of the file. + if (char2cells(wp->w_fill_chars.diff) > 1) + i = '-'; + else + i = wp->w_fill_chars.diff; + if (row + j > wp->w_height) + j = wp->w_height - row; + win_draw_end(wp, i, i, TRUE, row, row + (int)j, HLF_DED); + row += j; + } +#endif + } + else if (dollar_vcol == -1) + wp->w_botline = lnum; + + // Make sure the rest of the screen is blank. + // write the "eob" character from 'fillchars' to rows that aren't part + // of the file. + if (WIN_IS_POPUP(wp)) + win_draw_end(wp, ' ', ' ', FALSE, row, wp->w_height, HLF_AT); + else + win_draw_end(wp, wp->w_fill_chars.eob, ' ', FALSE, + row, wp->w_height, HLF_EOB); + } + +#ifdef SYN_TIME_LIMIT + disable_regexp_timeout(); + redrawtime_limit_set = FALSE; +#endif + + // Reset the type of redrawing required, the window has been updated. + wp->w_redr_type = 0; +#ifdef FEAT_DIFF + wp->w_old_topfill = wp->w_topfill; + wp->w_old_botfill = wp->w_botfill; +#endif + + if (dollar_vcol == -1) + { + // There is a trick with w_botline. If we invalidate it on each + // change that might modify it, this will cause a lot of expensive + // calls to plines() in update_topline() each time. Therefore the + // value of w_botline is often approximated, and this value is used to + // compute the value of w_topline. If the value of w_botline was + // wrong, check that the value of w_topline is correct (cursor is on + // the visible part of the text). If it's not, we need to redraw + // again. Mostly this just means scrolling up a few lines, so it + // doesn't look too bad. Only do this for the current window (where + // changes are relevant). + wp->w_valid |= VALID_BOTLINE; + if (wp == curwin && wp->w_botline != old_botline && !recursive) + { + win_T *wwp; +#if defined(FEAT_CONCEAL) + linenr_T old_topline = wp->w_topline; + int new_wcol = wp->w_wcol; +#endif + recursive = TRUE; + curwin->w_valid &= ~VALID_TOPLINE; + update_topline(); // may invalidate w_botline again + +#if defined(FEAT_CONCEAL) + if (old_wcol != new_wcol && (wp->w_valid & (VALID_WCOL|VALID_WROW)) + != (VALID_WCOL|VALID_WROW)) + { + // A win_line() call applied a fix to screen cursor column to + // accommodate concealment of cursor line, but in this call to + // update_topline() the cursor's row or column got invalidated. + // If they are left invalid, setcursor() will recompute them + // but there won't be any further win_line() call to re-fix the + // column and the cursor will end up misplaced. So we call + // cursor validation now and reapply the fix again (or call + // win_line() to do it for us). + validate_cursor(); + if (wp->w_wcol == old_wcol && wp->w_wrow == old_wrow + && old_topline == wp->w_topline) + wp->w_wcol = new_wcol; + else + redrawWinline(wp, wp->w_cursor.lnum); + } +#endif + // New redraw either due to updated topline or due to wcol fix. + if (wp->w_redr_type != 0) + { + // Don't update for changes in buffer again. + i = curbuf->b_mod_set; + curbuf->b_mod_set = FALSE; + j = curbuf->b_mod_xlines; + curbuf->b_mod_xlines = 0; + win_update(curwin); + curbuf->b_mod_set = i; + curbuf->b_mod_xlines = j; + } + // Other windows might have w_redr_type raised in update_topline(). + must_redraw = 0; + FOR_ALL_WINDOWS(wwp) + if (wwp->w_redr_type > must_redraw) + must_redraw = wwp->w_redr_type; + recursive = FALSE; + } + } + +#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) + // restore got_int, unless CTRL-C was hit while redrawing + if (!got_int) + got_int = save_got_int; +#endif +} + +#if defined(FEAT_NETBEANS_INTG) || defined(FEAT_GUI) +/* + * Prepare for updating one or more windows. + * Caller must check for "updating_screen" already set to avoid recursiveness. + */ + static void +update_prepare(void) +{ + cursor_off(); + updating_screen = TRUE; +#ifdef FEAT_GUI + // Remove the cursor before starting to do anything, because scrolling may + // make it difficult to redraw the text under it. + if (gui.in_use) + gui_undraw_cursor(); +#endif +#ifdef FEAT_SEARCH_EXTRA + start_search_hl(); +#endif +#ifdef FEAT_PROP_POPUP + // Update popup_mask if needed. + may_update_popup_mask(must_redraw); +#endif +} + +/* + * Finish updating one or more windows. + */ + static void +update_finish(void) +{ + if (redraw_cmdline || redraw_mode) + showmode(); + +# ifdef FEAT_SEARCH_EXTRA + end_search_hl(); +# endif + + after_updating_screen(TRUE); + +# ifdef FEAT_GUI + // Redraw the cursor and update the scrollbars when all screen updating is + // done. + if (gui.in_use) + { + out_flush_cursor(FALSE, FALSE); + gui_update_scrollbars(FALSE); + } +# endif +} +#endif + +#if defined(FEAT_NETBEANS_INTG) || defined(PROTO) + void +update_debug_sign(buf_T *buf, linenr_T lnum) +{ + win_T *wp; + int doit = FALSE; + +# ifdef FEAT_FOLDING + win_foldinfo.fi_level = 0; +# endif + + // update/delete a specific sign + redraw_buf_line_later(buf, lnum); + + // check if it resulted in the need to redraw a window + FOR_ALL_WINDOWS(wp) + if (wp->w_redr_type != 0) + doit = TRUE; + + // Return when there is nothing to do, screen updating is already + // happening (recursive call), messages on the screen or still starting up. + if (!doit || updating_screen + || State == MODE_ASKMORE || State == MODE_HITRETURN + || msg_scrolled +#ifdef FEAT_GUI + || gui.starting +#endif + || starting) + return; + + // update all windows that need updating + update_prepare(); + + FOR_ALL_WINDOWS(wp) + { + if (wp->w_redr_type != 0) + win_update(wp); + if (wp->w_redr_status) + win_redr_status(wp, FALSE); + } + + update_finish(); +} +#endif + +#if defined(FEAT_GUI) || defined(PROTO) +/* + * Update a single window, its status line and maybe the command line msg. + * Used for the GUI scrollbar. + */ + void +updateWindow(win_T *wp) +{ + // return if already busy updating + if (updating_screen) + return; + + update_prepare(); + +#ifdef FEAT_CLIPBOARD + // When Visual area changed, may have to update selection. + if (clip_star.available && clip_isautosel_star()) + clip_update_selection(&clip_star); + if (clip_plus.available && clip_isautosel_plus()) + clip_update_selection(&clip_plus); +#endif + + win_update(wp); + + // When the screen was cleared redraw the tab pages line. + if (redraw_tabline) + draw_tabline(); + + if (wp->w_redr_status || p_ru +# ifdef FEAT_STL_OPT + || *p_stl != NUL || *wp->w_p_stl != NUL +# endif + ) + win_redr_status(wp, FALSE); + +#ifdef FEAT_PROP_POPUP + // Display popup windows on top of everything. + update_popups(win_update); +#endif + + update_finish(); +} +#endif + +/* + * Redraw as soon as possible. When the command line is not scrolled redraw + * right away and restore what was on the command line. + * Return a code indicating what happened. + */ + int +redraw_asap(int type) +{ + int rows; + int cols = screen_Columns; + int r; + int ret = 0; + schar_T *screenline; // copy from ScreenLines[] + sattr_T *screenattr; // copy from ScreenAttrs[] + int i; + u8char_T *screenlineUC = NULL; // copy from ScreenLinesUC[] + u8char_T *screenlineC[MAX_MCO]; // copy from ScreenLinesC[][] + schar_T *screenline2 = NULL; // copy from ScreenLines2[] + + redraw_later(type); + if (msg_scrolled + || (State != MODE_NORMAL && State != MODE_NORMAL_BUSY) + || exiting) + return ret; + + // Allocate space to save the text displayed in the command line area. + rows = screen_Rows - cmdline_row; + screenline = LALLOC_MULT(schar_T, rows * cols); + screenattr = LALLOC_MULT(sattr_T, rows * cols); + if (screenline == NULL || screenattr == NULL) + ret = 2; + if (enc_utf8) + { + screenlineUC = LALLOC_MULT(u8char_T, rows * cols); + if (screenlineUC == NULL) + ret = 2; + for (i = 0; i < p_mco; ++i) + { + screenlineC[i] = LALLOC_MULT(u8char_T, rows * cols); + if (screenlineC[i] == NULL) + ret = 2; + } + } + if (enc_dbcs == DBCS_JPNU) + { + screenline2 = LALLOC_MULT(schar_T, rows * cols); + if (screenline2 == NULL) + ret = 2; + } + + if (ret != 2) + { + // Save the text displayed in the command line area. + for (r = 0; r < rows; ++r) + { + mch_memmove(screenline + r * cols, + ScreenLines + LineOffset[cmdline_row + r], + (size_t)cols * sizeof(schar_T)); + mch_memmove(screenattr + r * cols, + ScreenAttrs + LineOffset[cmdline_row + r], + (size_t)cols * sizeof(sattr_T)); + if (enc_utf8) + { + mch_memmove(screenlineUC + r * cols, + ScreenLinesUC + LineOffset[cmdline_row + r], + (size_t)cols * sizeof(u8char_T)); + for (i = 0; i < p_mco; ++i) + mch_memmove(screenlineC[i] + r * cols, + ScreenLinesC[i] + LineOffset[cmdline_row + r], + (size_t)cols * sizeof(u8char_T)); + } + if (enc_dbcs == DBCS_JPNU) + mch_memmove(screenline2 + r * cols, + ScreenLines2 + LineOffset[cmdline_row + r], + (size_t)cols * sizeof(schar_T)); + } + + update_screen(0); + ret = 3; + + if (must_redraw == 0) + { + int off = (int)(current_ScreenLine - ScreenLines); + + // Restore the text displayed in the command line area. + for (r = 0; r < rows; ++r) + { + mch_memmove(current_ScreenLine, + screenline + r * cols, + (size_t)cols * sizeof(schar_T)); + mch_memmove(ScreenAttrs + off, + screenattr + r * cols, + (size_t)cols * sizeof(sattr_T)); + if (enc_utf8) + { + mch_memmove(ScreenLinesUC + off, + screenlineUC + r * cols, + (size_t)cols * sizeof(u8char_T)); + for (i = 0; i < p_mco; ++i) + mch_memmove(ScreenLinesC[i] + off, + screenlineC[i] + r * cols, + (size_t)cols * sizeof(u8char_T)); + } + if (enc_dbcs == DBCS_JPNU) + mch_memmove(ScreenLines2 + off, + screenline2 + r * cols, + (size_t)cols * sizeof(schar_T)); + screen_line(curwin, cmdline_row + r, 0, cols, cols, 0); + } + ret = 4; + } + } + + vim_free(screenline); + vim_free(screenattr); + if (enc_utf8) + { + vim_free(screenlineUC); + for (i = 0; i < p_mco; ++i) + vim_free(screenlineC[i]); + } + if (enc_dbcs == DBCS_JPNU) + vim_free(screenline2); + + // Show the intro message when appropriate. + maybe_intro_message(); + + setcursor(); + + return ret; +} + +/* + * Invoked after an asynchronous callback is called. + * If an echo command was used the cursor needs to be put back where + * it belongs. If highlighting was changed a redraw is needed. + * If "call_update_screen" is FALSE don't call update_screen() when at the + * command line. + * If "redraw_message" is TRUE. + */ + void +redraw_after_callback(int call_update_screen, int do_message) +{ + ++redrawing_for_callback; + + if (State == MODE_HITRETURN || State == MODE_ASKMORE + || State == MODE_SETWSIZE || State == MODE_EXTERNCMD + || State == MODE_CONFIRM || exmode_active) + { + if (do_message) + repeat_message(); + } + else if (State & MODE_CMDLINE) + { + if (pum_visible()) + cmdline_pum_display(); + + // Don't redraw when in prompt_for_number(). + if (cmdline_row > 0) + { + // Redrawing only works when the screen didn't scroll. Don't clear + // wildmenu entries. + if (msg_scrolled == 0 + && wild_menu_showing == 0 + && call_update_screen) + update_screen(0); + + // Redraw in the same position, so that the user can continue + // editing the command. + redrawcmdline_ex(FALSE); + } + } + else if (State & (MODE_NORMAL | MODE_INSERT | MODE_TERMINAL)) + { + update_topline(); + validate_cursor(); + + // keep the command line if possible + update_screen(UPD_VALID_NO_UPDATE); + setcursor(); + + if (msg_scrolled == 0) + { + // don't want a hit-enter prompt when something else is displayed + msg_didany = FALSE; + need_wait_return = FALSE; + } + } + cursor_on(); +#ifdef FEAT_GUI + if (gui.in_use && !gui_mch_is_blink_off()) + // Don't update the cursor when it is blinking and off to avoid + // flicker. + out_flush_cursor(FALSE, FALSE); + else +#endif + out_flush(); + + --redrawing_for_callback; +} + +/* + * Redraw the current window later, with update_screen(type). + * Set must_redraw only if not already set to a higher value. + * E.g. if must_redraw is UPD_CLEAR, type UPD_NOT_VALID will do nothing. + */ + void +redraw_later(int type) +{ + redraw_win_later(curwin, type); +} + + void +redraw_win_later( + win_T *wp, + int type) +{ + if (!exiting && !redraw_not_allowed && wp->w_redr_type < type) + { + wp->w_redr_type = type; + if (type >= UPD_NOT_VALID) + wp->w_lines_valid = 0; + if (must_redraw < type) // must_redraw is the maximum of all windows + must_redraw = type; + } +} + +/* + * Force a complete redraw later. Also resets the highlighting. To be used + * after executing a shell command that messes up the screen. + */ + void +redraw_later_clear(void) +{ + redraw_all_later(UPD_CLEAR); + reset_screen_attr(); +} + +/* + * Mark all windows to be redrawn later. Except popup windows. + */ + void +redraw_all_later(int type) +{ + win_T *wp; + + FOR_ALL_WINDOWS(wp) + redraw_win_later(wp, type); + // This may be needed when switching tabs. + set_must_redraw(type); +} + +#if 0 // not actually used yet, it probably should +/* + * Mark all windows, including popup windows, to be redrawn. + */ + void +redraw_all_windows_later(int type) +{ + redraw_all_later(type); +#ifdef FEAT_PROP_POPUP + popup_redraw_all(); // redraw all popup windows +#endif +} +#endif + +/* + * Set "must_redraw" to "type" unless it already has a higher value + * or it is currently not allowed. + */ + void +set_must_redraw(int type) +{ + if (!redraw_not_allowed && must_redraw < type) + must_redraw = type; +} + +/* + * Mark all windows that are editing the current buffer to be updated later. + */ + void +redraw_curbuf_later(int type) +{ + redraw_buf_later(curbuf, type); +} + + void +redraw_buf_later(buf_T *buf, int type) +{ + win_T *wp; + + FOR_ALL_WINDOWS(wp) + { + if (wp->w_buffer == buf) + redraw_win_later(wp, type); + } +#if defined(FEAT_TERMINAL) && defined(FEAT_PROP_POPUP) + // terminal in popup window is not in list of windows + if (curwin->w_buffer == buf) + redraw_win_later(curwin, type); +#endif +} + +#if defined(FEAT_SIGNS) || defined(PROTO) + void +redraw_buf_line_later(buf_T *buf, linenr_T lnum) +{ + win_T *wp; + + FOR_ALL_WINDOWS(wp) + if (wp->w_buffer == buf && lnum >= wp->w_topline + && lnum < wp->w_botline) + redrawWinline(wp, lnum); +} +#endif + +#if defined(FEAT_JOB_CHANNEL) || defined(PROTO) + void +redraw_buf_and_status_later(buf_T *buf, int type) +{ + win_T *wp; + + if (wild_menu_showing != 0) + // Don't redraw while the command line completion is displayed, it + // would disappear. + return; + FOR_ALL_WINDOWS(wp) + { + if (wp->w_buffer == buf) + { + redraw_win_later(wp, type); + wp->w_redr_status = TRUE; + } + } +} +#endif + +/* + * mark all status lines for redraw; used after first :cd + */ + void +status_redraw_all(void) +{ + win_T *wp; + + FOR_ALL_WINDOWS(wp) + if (wp->w_status_height) + { + wp->w_redr_status = TRUE; + redraw_later(UPD_VALID); + } +} + +/* + * mark all status lines of the current buffer for redraw + */ + void +status_redraw_curbuf(void) +{ + win_T *wp; + + FOR_ALL_WINDOWS(wp) + if (wp->w_status_height != 0 && wp->w_buffer == curbuf) + { + wp->w_redr_status = TRUE; + redraw_later(UPD_VALID); + } +} + +/* + * Redraw all status lines that need to be redrawn. + */ + void +redraw_statuslines(void) +{ + win_T *wp; + + FOR_ALL_WINDOWS(wp) + if (wp->w_redr_status) + win_redr_status(wp, FALSE); + if (redraw_tabline) + draw_tabline(); +} + +/* + * Redraw all status lines at the bottom of frame "frp". + */ + void +win_redraw_last_status(frame_T *frp) +{ + if (frp->fr_layout == FR_LEAF) + frp->fr_win->w_redr_status = TRUE; + else if (frp->fr_layout == FR_ROW) + { + FOR_ALL_FRAMES(frp, frp->fr_child) + win_redraw_last_status(frp); + } + else // frp->fr_layout == FR_COL + { + frp = frp->fr_child; + while (frp->fr_next != NULL) + frp = frp->fr_next; + win_redraw_last_status(frp); + } +} + +/* + * Changed something in the current window, at buffer line "lnum", that + * requires that line and possibly other lines to be redrawn. + * Used when entering/leaving Insert mode with the cursor on a folded line. + * Used to remove the "$" from a change command. + * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot + * may become invalid and the whole window will have to be redrawn. + */ + void +redrawWinline( + win_T *wp, + linenr_T lnum) +{ + if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum) + wp->w_redraw_top = lnum; + if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum) + wp->w_redraw_bot = lnum; + redraw_win_later(wp, UPD_VALID); +} diff --git a/src/edit.c b/src/edit.c new file mode 100644 index 0000000..212efae --- /dev/null +++ b/src/edit.c @@ -0,0 +1,5426 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * edit.c: functions for Insert mode + */ + +#include "vim.h" + +#define BACKSPACE_CHAR 1 +#define BACKSPACE_WORD 2 +#define BACKSPACE_WORD_NOT_SPACE 3 +#define BACKSPACE_LINE 4 + +// Set when doing something for completion that may call edit() recursively, +// which is not allowed. +static int compl_busy = FALSE; + + +static void ins_ctrl_v(void); +static void insert_special(int, int, int); +static void redo_literal(int c); +static void start_arrow_common(pos_T *end_insert_pos, int change); +#ifdef FEAT_SPELL +static void check_spell_redraw(void); +#endif +static void stop_insert(pos_T *end_insert_pos, int esc, int nomove); +static int echeck_abbr(int); +static void mb_replace_pop_ins(int cc); +static void replace_flush(void); +static void replace_do_bs(int limit_col); +static int del_char_after_col(int limit_col); +static void ins_reg(void); +static void ins_ctrl_g(void); +static void ins_ctrl_hat(void); +static int ins_esc(long *count, int cmdchar, int nomove); +#ifdef FEAT_RIGHTLEFT +static void ins_ctrl_(void); +#endif +static int ins_start_select(int c); +static void ins_insert(int replaceState); +static void ins_ctrl_o(void); +static void ins_shift(int c, int lastc); +static void ins_del(void); +static int ins_bs(int c, int mode, int *inserted_space_p); +#if defined(FEAT_GUI_TABLINE) || defined(PROTO) +static void ins_tabline(int c); +#endif +static void ins_left(void); +static void ins_home(int c); +static void ins_end(int c); +static void ins_s_left(void); +static void ins_right(void); +static void ins_s_right(void); +static void ins_up(int startcol); +static void ins_pageup(void); +static void ins_down(int startcol); +static void ins_pagedown(void); +#ifdef FEAT_DND +static void ins_drop(void); +#endif +static int ins_tab(void); +#ifdef FEAT_DIGRAPHS +static int ins_digraph(void); +#endif +static int ins_ctrl_ey(int tc); +#if defined(FEAT_EVAL) +static char_u *do_insert_char_pre(int c); +#endif + +static colnr_T Insstart_textlen; // length of line when insert started +static colnr_T Insstart_blank_vcol; // vcol for first inserted blank +static int update_Insstart_orig = TRUE; // set Insstart_orig to Insstart + +static char_u *last_insert = NULL; // the text of the previous insert, + // K_SPECIAL and CSI are escaped +static int last_insert_skip; // nr of chars in front of previous insert +static int new_insert_skip; // nr of chars in front of current insert +static int did_restart_edit; // "restart_edit" when calling edit() + +static int can_cindent; // may do cindenting on this line + +#ifdef FEAT_RIGHTLEFT +static int revins_on; // reverse insert mode on +static int revins_chars; // how much to skip after edit +static int revins_legal; // was the last char 'legal'? +static int revins_scol; // start column of revins session +#endif + +static int ins_need_undo; // call u_save() before inserting a + // char. Set when edit() is called. + // after that arrow_used is used. + +static int dont_sync_undo = FALSE; // CTRL-G U prevents syncing undo for + // the next left/right cursor key + +/* + * edit(): Start inserting text. + * + * "cmdchar" can be: + * 'i' normal insert command + * 'a' normal append command + * K_PS bracketed paste + * 'R' replace command + * 'r' "r" command: insert one . Note: count can be > 1, for redo, + * but still only one is inserted. The is not used for redo. + * 'g' "gI" command. + * 'V' "gR" command for Virtual Replace mode. + * 'v' "gr" command for single character Virtual Replace mode. + * + * This function is not called recursively. For CTRL-O commands, it returns + * and lets the caller handle the Normal-mode command. + * + * Return TRUE if a CTRL-O command caused the return (insert mode pending). + */ + int +edit( + int cmdchar, + int startln, // if set, insert at start of line + long count) +{ + int c = 0; + char_u *ptr; + int lastc = 0; + int mincol; + static linenr_T o_lnum = 0; + int i; + int did_backspace = TRUE; // previous char was backspace + int line_is_white = FALSE; // line is empty before insert + linenr_T old_topline = 0; // topline before insertion +#ifdef FEAT_DIFF + int old_topfill = -1; +#endif + int inserted_space = FALSE; // just inserted a space + int replaceState = MODE_REPLACE; + int nomove = FALSE; // don't move cursor on return +#ifdef FEAT_JOB_CHANNEL + int cmdchar_todo = cmdchar; +#endif +#ifdef FEAT_CONCEAL + int cursor_line_was_concealed; +#endif + + // Remember whether editing was restarted after CTRL-O. + did_restart_edit = restart_edit; + + // sleep before redrawing, needed for "CTRL-O :" that results in an + // error message + check_for_delay(TRUE); + + // set Insstart_orig to Insstart + update_Insstart_orig = TRUE; + +#ifdef HAVE_SANDBOX + // Don't allow inserting in the sandbox. + if (sandbox != 0) + { + emsg(_(e_not_allowed_in_sandbox)); + return FALSE; + } +#endif + // Don't allow changes in the buffer while editing the cmdline. The + // caller of getcmdline() may get confused. + // Don't allow recursive insert mode when busy with completion. + if (textlock != 0 || ins_compl_active() || compl_busy || pum_visible()) + { + emsg(_(e_not_allowed_to_change_text_or_change_window)); + return FALSE; + } + ins_compl_clear(); // clear stuff for CTRL-X mode + + /* + * Trigger InsertEnter autocommands. Do not do this for "r" or "grx". + */ + if (cmdchar != 'r' && cmdchar != 'v') + { + pos_T save_cursor = curwin->w_cursor; + +#ifdef FEAT_EVAL + if (cmdchar == 'R') + ptr = (char_u *)"r"; + else if (cmdchar == 'V') + ptr = (char_u *)"v"; + else + ptr = (char_u *)"i"; + set_vim_var_string(VV_INSERTMODE, ptr, 1); + set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char +#endif + ins_apply_autocmds(EVENT_INSERTENTER); + + // Check for changed highlighting, e.g. for ModeMsg. + if (need_highlight_changed) + highlight_changed(); + + // Make sure the cursor didn't move. Do call check_cursor_col() in + // case the text was modified. Since Insert mode was not started yet + // a call to check_cursor_col() may move the cursor, especially with + // the "A" command, thus set State to avoid that. Also check that the + // line number is still valid (lines may have been deleted). + // Do not restore if v:char was set to a non-empty string. + if (!EQUAL_POS(curwin->w_cursor, save_cursor) +#ifdef FEAT_EVAL + && *get_vim_var_str(VV_CHAR) == NUL +#endif + && save_cursor.lnum <= curbuf->b_ml.ml_line_count) + { + int save_state = State; + + curwin->w_cursor = save_cursor; + State = MODE_INSERT; + check_cursor_col(); + State = save_state; + } + } + +#ifdef FEAT_CONCEAL + // Check if the cursor line was concealed before changing State. + cursor_line_was_concealed = curwin->w_p_cole > 0 + && conceal_cursor_line(curwin); +#endif + + /* + * When doing a paste with the middle mouse button, Insstart is set to + * where the paste started. + */ + if (where_paste_started.lnum != 0) + Insstart = where_paste_started; + else + { + Insstart = curwin->w_cursor; + if (startln) + Insstart.col = 0; + } + Insstart_textlen = (colnr_T)linetabsize_str(ml_get_curline()); + Insstart_blank_vcol = MAXCOL; + if (!did_ai) + ai_col = 0; + + if (cmdchar != NUL && restart_edit == 0) + { + ResetRedobuff(); + AppendNumberToRedobuff(count); + if (cmdchar == 'V' || cmdchar == 'v') + { + // "gR" or "gr" command + AppendCharToRedobuff('g'); + AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R'); + } + else + { + if (cmdchar == K_PS) + AppendCharToRedobuff('a'); + else + AppendCharToRedobuff(cmdchar); + if (cmdchar == 'g') // "gI" command + AppendCharToRedobuff('I'); + else if (cmdchar == 'r') // "r" command + count = 1; // insert only one + } + } + + if (cmdchar == 'R') + { + State = MODE_REPLACE; + } + else if (cmdchar == 'V' || cmdchar == 'v') + { + State = MODE_VREPLACE; + replaceState = MODE_VREPLACE; + orig_line_count = curbuf->b_ml.ml_line_count; + vr_lines_changed = 1; + } + else + State = MODE_INSERT; + + may_trigger_modechanged(); + stop_insert_mode = FALSE; + +#ifdef FEAT_CONCEAL + // Check if the cursor line needs redrawing after changing State. If + // 'concealcursor' is "n" it needs to be redrawn without concealing. + conceal_check_cursor_line(cursor_line_was_concealed); +#endif + + // Need to position cursor again when on a TAB and when on a char with + // virtual text. + if (gchar_cursor() == TAB +#ifdef FEAT_PROP_POPUP + || curbuf->b_has_textprop +#endif + ) + curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); + + /* + * Enable langmap or IME, indicated by 'iminsert'. + * Note that IME may enabled/disabled without us noticing here, thus the + * 'iminsert' value may not reflect what is actually used. It is updated + * when hitting . + */ + if (curbuf->b_p_iminsert == B_IMODE_LMAP) + State |= MODE_LANGMAP; +#ifdef HAVE_INPUT_METHOD + im_set_active(curbuf->b_p_iminsert == B_IMODE_IM); +#endif + + setmouse(); + clear_showcmd(); +#ifdef FEAT_RIGHTLEFT + // there is no reverse replace mode + revins_on = (State == MODE_INSERT && p_ri); + if (revins_on) + undisplay_dollar(); + revins_chars = 0; + revins_legal = 0; + revins_scol = -1; +#endif + if (!p_ek) + { + MAY_WANT_TO_LOG_THIS; + + // Disable bracketed paste mode, we won't recognize the escape + // sequences. + out_str(T_BD); + + // Disable modifyOtherKeys, keys with modifiers would cause exiting + // Insert mode. + out_str_t_TE(); + } + + /* + * Handle restarting Insert mode. + * Don't do this for "CTRL-O ." (repeat an insert): In that case we get + * here with something in the stuff buffer. + */ + if (restart_edit != 0 && stuff_empty()) + { + /* + * After a paste we consider text typed to be part of the insert for + * the pasted text. You can backspace over the pasted text too. + */ + if (where_paste_started.lnum) + arrow_used = FALSE; + else + arrow_used = TRUE; + restart_edit = 0; + + /* + * If the cursor was after the end-of-line before the CTRL-O and it is + * now at the end-of-line, put it after the end-of-line (this is not + * correct in very rare cases). + * Also do this if curswant is greater than the current virtual + * column. Eg after "^O$" or "^O80|". + */ + validate_virtcol(); + update_curswant(); + if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum) + || curwin->w_curswant > curwin->w_virtcol) + && *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL) + { + if (ptr[1] == NUL) + ++curwin->w_cursor.col; + else if (has_mbyte) + { + i = (*mb_ptr2len)(ptr); + if (ptr[i] == NUL) + curwin->w_cursor.col += i; + } + } + ins_at_eol = FALSE; + } + else + arrow_used = FALSE; + + // we are in insert mode now, don't need to start it anymore + need_start_insertmode = FALSE; + + // Need to save the line for undo before inserting the first char. + ins_need_undo = TRUE; + + where_paste_started.lnum = 0; + can_cindent = TRUE; +#ifdef FEAT_FOLDING + // The cursor line is not in a closed fold, unless 'insertmode' is set or + // restarting. + if (!p_im && did_restart_edit == 0) + foldOpenCursor(); +#endif + + /* + * If 'showmode' is set, show the current (insert/replace/..) mode. + * A warning message for changing a readonly file is given here, before + * actually changing anything. It's put after the mode, if any. + */ + i = 0; + if (p_smd && msg_silent == 0) + i = showmode(); + + if (!p_im && did_restart_edit == 0) + change_warning(i == 0 ? 0 : i + 1); + +#ifdef CURSOR_SHAPE + ui_cursor_shape(); // may show different cursor shape +#endif +#ifdef FEAT_DIGRAPHS + do_digraph(-1); // clear digraphs +#endif + + /* + * Get the current length of the redo buffer, those characters have to be + * skipped if we want to get to the inserted characters. + */ + ptr = get_inserted(); + if (ptr == NULL) + new_insert_skip = 0; + else + { + new_insert_skip = (int)STRLEN(ptr); + vim_free(ptr); + } + + old_indent = 0; + + /* + * Main loop in Insert mode: repeat until Insert mode is left. + */ + for (;;) + { +#ifdef FEAT_RIGHTLEFT + if (!revins_legal) + revins_scol = -1; // reset on illegal motions + else + revins_legal = 0; +#endif + if (arrow_used) // don't repeat insert when arrow key used + count = 0; + + if (update_Insstart_orig) + Insstart_orig = Insstart; + + if (stop_insert_mode && !ins_compl_active()) + { + // ":stopinsert" used or 'insertmode' reset + count = 0; + goto doESCkey; + } + + // set curwin->w_curswant for next K_DOWN or K_UP + if (!arrow_used) + curwin->w_set_curswant = TRUE; + + // If there is no typeahead may check for timestamps (e.g., for when a + // menu invoked a shell command). + if (stuff_empty()) + { + did_check_timestamps = FALSE; + if (need_check_timestamps) + check_timestamps(FALSE); + } + + /* + * When emsg() was called msg_scroll will have been set. + */ + msg_scroll = FALSE; + +#ifdef FEAT_GUI + // When 'mousefocus' is set a mouse movement may have taken us to + // another window. "need_mouse_correct" may then be set because of an + // autocommand. + if (need_mouse_correct) + gui_mouse_correct(); +#endif + +#ifdef FEAT_FOLDING + // Open fold at the cursor line, according to 'foldopen'. + if (fdo_flags & FDO_INSERT) + foldOpenCursor(); + // Close folds where the cursor isn't, according to 'foldclose' + if (!char_avail()) + foldCheckClose(); +#endif + +#ifdef FEAT_JOB_CHANNEL + if (bt_prompt(curbuf)) + { + init_prompt(cmdchar_todo); + cmdchar_todo = NUL; + } +#endif + + /* + * If we inserted a character at the last position of the last line in + * the window, scroll the window one line up. This avoids an extra + * redraw. + * This is detected when the cursor column is smaller after inserting + * something. + * Don't do this when the topline changed already, it has + * already been adjusted (by insertchar() calling open_line())). + */ + if (curbuf->b_mod_set + && curwin->w_p_wrap + && !did_backspace + && curwin->w_topline == old_topline +#ifdef FEAT_DIFF + && curwin->w_topfill == old_topfill +#endif + ) + { + mincol = curwin->w_wcol; + validate_cursor_col(); + + if ( +#ifdef FEAT_VARTABS + curwin->w_wcol < mincol - tabstop_at( + get_nolist_virtcol(), curbuf->b_p_ts, + curbuf->b_p_vts_array) +#else + (int)curwin->w_wcol < mincol - curbuf->b_p_ts +#endif + && curwin->w_wrow == W_WINROW(curwin) + + curwin->w_height - 1 - get_scrolloff_value() + && (curwin->w_cursor.lnum != curwin->w_topline +#ifdef FEAT_DIFF + || curwin->w_topfill > 0 +#endif + )) + { +#ifdef FEAT_DIFF + if (curwin->w_topfill > 0) + --curwin->w_topfill; + else +#endif +#ifdef FEAT_FOLDING + if (hasFolding(curwin->w_topline, NULL, &old_topline)) + set_topline(curwin, old_topline + 1); + else +#endif + set_topline(curwin, curwin->w_topline + 1); + } + } + + // May need to adjust w_topline to show the cursor. + update_topline(); + + did_backspace = FALSE; + + validate_cursor(); // may set must_redraw + + /* + * Redraw the display when no characters are waiting. + * Also shows mode, ruler and positions cursor. + */ + ins_redraw(TRUE); + + if (curwin->w_p_scb) + do_check_scrollbind(TRUE); + + if (curwin->w_p_crb) + do_check_cursorbind(); + update_curswant(); + old_topline = curwin->w_topline; +#ifdef FEAT_DIFF + old_topfill = curwin->w_topfill; +#endif + +#ifdef USE_ON_FLY_SCROLL + dont_scroll = FALSE; // allow scrolling here +#endif + // May request the keyboard protocol state now. + may_send_t_RK(); + + /* + * Get a character for Insert mode. Ignore K_IGNORE and K_NOP. + */ + if (c != K_CURSORHOLD) + lastc = c; // remember the previous char for CTRL-D + + // After using CTRL-G U the next cursor key will not break undo. + if (dont_sync_undo == MAYBE) + dont_sync_undo = TRUE; + else + dont_sync_undo = FALSE; + if (cmdchar == K_PS) + // Got here from normal mode when bracketed paste started. + c = K_PS; + else + do + { + c = safe_vgetc(); + + if (stop_insert_mode +#ifdef FEAT_TERMINAL + || (c == K_IGNORE && term_use_loop()) +#endif + ) + { + // Insert mode ended, possibly from a callback, or a timer + // must have opened a terminal window. + if (c != K_IGNORE && c != K_NOP) + vungetc(c); + count = 0; + nomove = TRUE; + ins_compl_prep(ESC); + goto doESCkey; + } + } while (c == K_IGNORE || c == K_NOP); + + // Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. + did_cursorhold = TRUE; + +#ifdef FEAT_RIGHTLEFT + if (p_hkmap && KeyTyped) + c = hkmap(c); // Hebrew mode mapping +#endif + + // If the window was made so small that nothing shows, make it at least + // one line and one column when typing. + if (KeyTyped && !KeyStuffed) + win_ensure_size(); + + /* + * Special handling of keys while the popup menu is visible or wanted + * and the cursor is still in the completed word. Only when there is + * a match, skip this when no matches were found. + */ + if (ins_compl_active() + && pum_wanted() + && curwin->w_cursor.col >= ins_compl_col() + && ins_compl_has_shown_match()) + { + // BS: Delete one character from "compl_leader". + if ((c == K_BS || c == Ctrl_H) + && curwin->w_cursor.col > ins_compl_col() + && (c = ins_compl_bs()) == NUL) + continue; + + // When no match was selected or it was edited. + if (!ins_compl_used_match()) + { + // CTRL-L: Add one character from the current match to + // "compl_leader". Except when at the original match and + // there is nothing to add, CTRL-L works like CTRL-P then. + if (c == Ctrl_L + && (!ctrl_x_mode_line_or_eval() + || ins_compl_long_shown_match())) + { + ins_compl_addfrommatch(); + continue; + } + + // A non-white character that fits in with the current + // completion: Add to "compl_leader". + if (ins_compl_accept_char(c)) + { +#if defined(FEAT_EVAL) + // Trigger InsertCharPre. + char_u *str = do_insert_char_pre(c); + char_u *p; + + if (str != NULL) + { + for (p = str; *p != NUL; MB_PTR_ADV(p)) + ins_compl_addleader(PTR2CHAR(p)); + vim_free(str); + } + else +#endif + ins_compl_addleader(c); + continue; + } + + // Pressing CTRL-Y selects the current match. When + // ins_compl_enter_selects() is set the Enter key does the + // same. + if ((c == Ctrl_Y || (ins_compl_enter_selects() + && (c == CAR || c == K_KENTER || c == NL))) + && stop_arrow() == OK) + { + ins_compl_delete(); + ins_compl_insert(FALSE); + } + } + } + + // Prepare for or stop CTRL-X mode. This doesn't do completion, but + // it does fix up the text when finishing completion. + ins_compl_init_get_longest(); + if (ins_compl_prep(c)) + continue; + + // CTRL-\ CTRL-N goes to Normal mode, + // CTRL-\ CTRL-G goes to mode selected with 'insertmode', + // CTRL-\ CTRL-O is like CTRL-O but without moving the cursor. + if (c == Ctrl_BSL) + { + // may need to redraw when no more chars available now + ins_redraw(FALSE); + ++no_mapping; + ++allow_keys; + c = plain_vgetc(); + --no_mapping; + --allow_keys; + if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O) + { + // it's something else + vungetc(c); + c = Ctrl_BSL; + } + else if (c == Ctrl_G && p_im) + continue; + else + { + if (c == Ctrl_O) + { + ins_ctrl_o(); + ins_at_eol = FALSE; // cursor keeps its column + nomove = TRUE; + } + count = 0; + goto doESCkey; + } + } + +#ifdef FEAT_DIGRAPHS + c = do_digraph(c); +#endif + + if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode_cmdline()) + goto docomplete; + if (c == Ctrl_V || c == Ctrl_Q) + { + ins_ctrl_v(); + c = Ctrl_V; // pretend CTRL-V is last typed character + continue; + } + + if (cindent_on() && ctrl_x_mode_none()) + { + // A key name preceded by a bang means this key is not to be + // inserted. Skip ahead to the re-indenting below. + // A key name preceded by a star means that indenting has to be + // done before inserting the key. + line_is_white = inindent(0); + if (in_cinkeys(c, '!', line_is_white)) + goto force_cindent; + if (can_cindent && in_cinkeys(c, '*', line_is_white) + && stop_arrow() == OK) + do_c_expr_indent(); + } + +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + switch (c) + { + case K_LEFT: c = K_RIGHT; break; + case K_S_LEFT: c = K_S_RIGHT; break; + case K_C_LEFT: c = K_C_RIGHT; break; + case K_RIGHT: c = K_LEFT; break; + case K_S_RIGHT: c = K_S_LEFT; break; + case K_C_RIGHT: c = K_C_LEFT; break; + } +#endif + + /* + * If 'keymodel' contains "startsel", may start selection. If it + * does, a CTRL-O and c will be stuffed, we need to get these + * characters. + */ + if (ins_start_select(c)) + continue; + + /* + * The big switch to handle a character in insert mode. + */ + switch (c) + { + case ESC: // End input mode + if (echeck_abbr(ESC + ABBR_OFF)) + break; + // FALLTHROUGH + + case Ctrl_C: // End input mode + if (c == Ctrl_C && cmdwin_type != 0) + { + // Close the cmdline window. + cmdwin_result = K_IGNORE; + got_int = FALSE; // don't stop executing autocommands et al. + nomove = TRUE; + goto doESCkey; + } +#ifdef FEAT_JOB_CHANNEL + if (c == Ctrl_C && bt_prompt(curbuf)) + { + if (invoke_prompt_interrupt()) + { + if (!bt_prompt(curbuf)) + // buffer changed to a non-prompt buffer, get out of + // Insert mode + goto doESCkey; + break; + } + } +#endif + +#ifdef UNIX +do_intr: +#endif + // when 'insertmode' set, and not halfway a mapping, don't leave + // Insert mode + if (goto_im()) + { + if (got_int) + { + (void)vgetc(); // flush all buffers + got_int = FALSE; + } + else + vim_beep(BO_IM); + break; + } +doESCkey: + /* + * This is the ONLY return from edit()! + */ + // Always update o_lnum, so that a "CTRL-O ." that adds a line + // still puts the cursor back after the inserted text. + if (ins_at_eol && gchar_cursor() == NUL) + o_lnum = curwin->w_cursor.lnum; + + if (ins_esc(&count, cmdchar, nomove)) + { + // When CTRL-C was typed got_int will be set, with the result + // that the autocommands won't be executed. When mapped got_int + // is not set, but let's keep the behavior the same. + if (cmdchar != 'r' && cmdchar != 'v' && c != Ctrl_C) + ins_apply_autocmds(EVENT_INSERTLEAVE); + did_cursorhold = FALSE; + return (c == Ctrl_O); + } + continue; + + case Ctrl_Z: // suspend when 'insertmode' set + if (!p_im) + goto normalchar; // insert CTRL-Z as normal char + do_cmdline_cmd((char_u *)"stop"); +#ifdef CURSOR_SHAPE + ui_cursor_shape(); // may need to update cursor shape +#endif + continue; + + case Ctrl_O: // execute one command +#ifdef FEAT_COMPL_FUNC + if (ctrl_x_mode_omni()) + goto docomplete; +#endif + if (echeck_abbr(Ctrl_O + ABBR_OFF)) + break; + ins_ctrl_o(); + + // don't move the cursor left when 'virtualedit' has "onemore". + if (get_ve_flags() & VE_ONEMORE) + { + ins_at_eol = FALSE; + nomove = TRUE; + } + count = 0; + goto doESCkey; + + case K_INS: // toggle insert/replace mode + case K_KINS: + ins_insert(replaceState); + break; + + case K_SELECT: // end of Select mode mapping - ignore + break; + + case K_HELP: // Help key works like + case K_F1: + case K_XF1: + stuffcharReadbuff(K_HELP); + if (p_im) + need_start_insertmode = TRUE; + goto doESCkey; + +#ifdef FEAT_NETBEANS_INTG + case K_F21: // NetBeans command + ++no_mapping; // don't map the next key hits + i = plain_vgetc(); + --no_mapping; + netbeans_keycommand(i); + break; +#endif + + case K_ZERO: // Insert the previously inserted text. + case NUL: + case Ctrl_A: + // For ^@ the trailing ESC will end the insert, unless there is an + // error. + if (stuff_inserted(NUL, 1L, (c == Ctrl_A)) == FAIL + && c != Ctrl_A && !p_im) + goto doESCkey; // quit insert mode + inserted_space = FALSE; + break; + + case Ctrl_R: // insert the contents of a register + ins_reg(); + auto_format(FALSE, TRUE); + inserted_space = FALSE; + break; + + case Ctrl_G: // commands starting with CTRL-G + ins_ctrl_g(); + break; + + case Ctrl_HAT: // switch input mode and/or langmap + ins_ctrl_hat(); + break; + +#ifdef FEAT_RIGHTLEFT + case Ctrl__: // switch between languages + if (!p_ari) + goto normalchar; + ins_ctrl_(); + break; +#endif + + case Ctrl_D: // Make indent one shiftwidth smaller. +#if defined(FEAT_FIND_ID) + if (ctrl_x_mode_path_defines()) + goto docomplete; +#endif + // FALLTHROUGH + + case Ctrl_T: // Make indent one shiftwidth greater. + if (c == Ctrl_T && ctrl_x_mode_thesaurus()) + { + if (has_compl_option(FALSE)) + goto docomplete; + break; + } + + ins_shift(c, lastc); + auto_format(FALSE, TRUE); + inserted_space = FALSE; + break; + + case K_DEL: // delete character under the cursor + case K_KDEL: + ins_del(); + auto_format(FALSE, TRUE); + break; + + case K_BS: // delete character before the cursor + case K_S_BS: + case Ctrl_H: + did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space); + auto_format(FALSE, TRUE); + break; + + case Ctrl_W: // delete word before the cursor +#ifdef FEAT_JOB_CHANNEL + if (bt_prompt(curbuf) && (mod_mask & MOD_MASK_SHIFT) == 0) + { + // In a prompt window CTRL-W is used for window commands. + // Use Shift-CTRL-W to delete a word. + stuffcharReadbuff(Ctrl_W); + restart_edit = 'A'; + nomove = TRUE; + count = 0; + goto doESCkey; + } +#endif + did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space); + auto_format(FALSE, TRUE); + break; + + case Ctrl_U: // delete all inserted text in current line +# ifdef FEAT_COMPL_FUNC + // CTRL-X CTRL-U completes with 'completefunc'. + if (ctrl_x_mode_function()) + goto docomplete; +# endif + did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space); + auto_format(FALSE, TRUE); + inserted_space = FALSE; + break; + + case K_LEFTMOUSE: // mouse keys + case K_LEFTMOUSE_NM: + case K_LEFTDRAG: + case K_LEFTRELEASE: + case K_LEFTRELEASE_NM: + case K_MOUSEMOVE: + case K_MIDDLEMOUSE: + case K_MIDDLEDRAG: + case K_MIDDLERELEASE: + case K_RIGHTMOUSE: + case K_RIGHTDRAG: + case K_RIGHTRELEASE: + case K_X1MOUSE: + case K_X1DRAG: + case K_X1RELEASE: + case K_X2MOUSE: + case K_X2DRAG: + case K_X2RELEASE: + ins_mouse(c); + break; + + case K_MOUSEDOWN: // Default action for scroll wheel up: scroll up + ins_mousescroll(MSCR_DOWN); + break; + + case K_MOUSEUP: // Default action for scroll wheel down: scroll down + ins_mousescroll(MSCR_UP); + break; + + case K_MOUSELEFT: // Scroll wheel left + ins_mousescroll(MSCR_LEFT); + break; + + case K_MOUSERIGHT: // Scroll wheel right + ins_mousescroll(MSCR_RIGHT); + break; + + case K_PS: + bracketed_paste(PASTE_INSERT, FALSE, NULL); + if (cmdchar == K_PS) + // invoked from normal mode, bail out + goto doESCkey; + break; + case K_PE: + // Got K_PE without K_PS, ignore. + break; + +#ifdef FEAT_GUI_TABLINE + case K_TABLINE: + case K_TABMENU: + ins_tabline(c); + break; +#endif + + case K_IGNORE: // Something mapped to nothing + break; + + case K_COMMAND: // command + case K_SCRIPT_COMMAND: // command + { + do_cmdkey_command(c, 0); + +#ifdef FEAT_TERMINAL + if (term_use_loop()) + // Started a terminal that gets the input, exit Insert mode. + goto doESCkey; +#endif + if (curbuf->b_u_synced) + // The command caused undo to be synced. Need to save the + // line for undo before inserting the next char. + ins_need_undo = TRUE; + } + break; + + case K_CURSORHOLD: // Didn't type something for a while. + ins_apply_autocmds(EVENT_CURSORHOLDI); + did_cursorhold = TRUE; + // If CTRL-G U was used apply it to the next typed key. + if (dont_sync_undo == TRUE) + dont_sync_undo = MAYBE; + break; + +#ifdef FEAT_GUI_MSWIN + // On MS-Windows ignore , we get it when closing the window + // was cancelled. + case K_F4: + if (mod_mask != MOD_MASK_ALT) + goto normalchar; + break; +#endif + +#ifdef FEAT_GUI + case K_VER_SCROLLBAR: + ins_scroll(); + break; + + case K_HOR_SCROLLBAR: + ins_horscroll(); + break; +#endif + + case K_HOME: // + case K_KHOME: + case K_S_HOME: + case K_C_HOME: + ins_home(c); + break; + + case K_END: // + case K_KEND: + case K_S_END: + case K_C_END: + ins_end(c); + break; + + case K_LEFT: // + if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) + ins_s_left(); + else + ins_left(); + break; + + case K_S_LEFT: // + case K_C_LEFT: + ins_s_left(); + break; + + case K_RIGHT: // + if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) + ins_s_right(); + else + ins_right(); + break; + + case K_S_RIGHT: // + case K_C_RIGHT: + ins_s_right(); + break; + + case K_UP: // + if (pum_visible()) + goto docomplete; + if (mod_mask & MOD_MASK_SHIFT) + ins_pageup(); + else + ins_up(FALSE); + break; + + case K_S_UP: // + case K_PAGEUP: + case K_KPAGEUP: + if (pum_visible()) + goto docomplete; + ins_pageup(); + break; + + case K_DOWN: // + if (pum_visible()) + goto docomplete; + if (mod_mask & MOD_MASK_SHIFT) + ins_pagedown(); + else + ins_down(FALSE); + break; + + case K_S_DOWN: // + case K_PAGEDOWN: + case K_KPAGEDOWN: + if (pum_visible()) + goto docomplete; + ins_pagedown(); + break; + +#ifdef FEAT_DND + case K_DROP: // drag-n-drop event + ins_drop(); + break; +#endif + + case K_S_TAB: // When not mapped, use like a normal TAB + c = TAB; + // FALLTHROUGH + + case TAB: // TAB or Complete patterns along path +#if defined(FEAT_FIND_ID) + if (ctrl_x_mode_path_patterns()) + goto docomplete; +#endif + inserted_space = FALSE; + if (ins_tab()) + goto normalchar; // insert TAB as a normal char + auto_format(FALSE, TRUE); + break; + + case K_KENTER: // + c = CAR; + // FALLTHROUGH + case CAR: + case NL: +#if defined(FEAT_QUICKFIX) + // In a quickfix window a jumps to the error under the + // cursor. + if (bt_quickfix(curbuf) && c == CAR) + { + if (curwin->w_llist_ref == NULL) // quickfix window + do_cmdline_cmd((char_u *)".cc"); + else // location list window + do_cmdline_cmd((char_u *)".ll"); + break; + } +#endif + if (cmdwin_type != 0) + { + // Execute the command in the cmdline window. + cmdwin_result = CAR; + goto doESCkey; + } +#ifdef FEAT_JOB_CHANNEL + if (bt_prompt(curbuf)) + { + invoke_prompt_callback(); + if (!bt_prompt(curbuf)) + // buffer changed to a non-prompt buffer, get out of + // Insert mode + goto doESCkey; + break; + } +#endif + if (ins_eol(c) == FAIL && !p_im) + goto doESCkey; // out of memory + auto_format(FALSE, FALSE); + inserted_space = FALSE; + break; + + case Ctrl_K: // digraph or keyword completion + if (ctrl_x_mode_dictionary()) + { + if (has_compl_option(TRUE)) + goto docomplete; + break; + } +#ifdef FEAT_DIGRAPHS + c = ins_digraph(); + if (c == NUL) + break; +#endif + goto normalchar; + + case Ctrl_X: // Enter CTRL-X mode + ins_ctrl_x(); + break; + + case Ctrl_RSB: // Tag name completion after ^X + if (!ctrl_x_mode_tags()) + goto normalchar; + goto docomplete; + + case Ctrl_F: // File name completion after ^X + if (!ctrl_x_mode_files()) + goto normalchar; + goto docomplete; + + case 's': // Spelling completion after ^X + case Ctrl_S: + if (!ctrl_x_mode_spell()) + goto normalchar; + goto docomplete; + + case Ctrl_L: // Whole line completion after ^X + if (!ctrl_x_mode_whole_line()) + { + // CTRL-L with 'insertmode' set: Leave Insert mode + if (p_im) + { + if (echeck_abbr(Ctrl_L + ABBR_OFF)) + break; + goto doESCkey; + } + goto normalchar; + } + // FALLTHROUGH + + case Ctrl_P: // Do previous/next pattern completion + case Ctrl_N: + // if 'complete' is empty then plain ^P is no longer special, + // but it is under other ^X modes + if (*curbuf->b_p_cpt == NUL + && (ctrl_x_mode_normal() || ctrl_x_mode_whole_line()) + && !compl_status_local()) + goto normalchar; + +docomplete: + compl_busy = TRUE; +#ifdef FEAT_FOLDING + disable_fold_update++; // don't redraw folds here +#endif + if (ins_complete(c, TRUE) == FAIL) + compl_status_clear(); +#ifdef FEAT_FOLDING + disable_fold_update--; +#endif + compl_busy = FALSE; + can_si = may_do_si(); // allow smartindenting + break; + + case Ctrl_Y: // copy from previous line or scroll down + case Ctrl_E: // copy from next line or scroll up + c = ins_ctrl_ey(c); + break; + + default: +#ifdef UNIX + if (c == intr_char) // special interrupt char + goto do_intr; +#endif + +normalchar: + /* + * Insert a normal character. + */ +#if defined(FEAT_EVAL) + if (!p_paste) + { + // Trigger InsertCharPre. + char_u *str = do_insert_char_pre(c); + char_u *p; + + if (str != NULL) + { + if (*str != NUL && stop_arrow() != FAIL) + { + // Insert the new value of v:char literally. + for (p = str; *p != NUL; MB_PTR_ADV(p)) + { + c = PTR2CHAR(p); + if (c == CAR || c == K_KENTER || c == NL) + ins_eol(c); + else + ins_char(c); + } + AppendToRedobuffLit(str, -1); + } + vim_free(str); + c = NUL; + } + + // If the new value is already inserted or an empty string + // then don't insert any character. + if (c == NUL) + break; + } +#endif + // Try to perform smart-indenting. + ins_try_si(c); + + if (c == ' ') + { + inserted_space = TRUE; + if (inindent(0)) + can_cindent = FALSE; + if (Insstart_blank_vcol == MAXCOL + && curwin->w_cursor.lnum == Insstart.lnum) + Insstart_blank_vcol = get_nolist_virtcol(); + } + + // Insert a normal character and check for abbreviations on a + // special character. Let CTRL-] expand abbreviations without + // inserting it. + if (vim_iswordc(c) || (!echeck_abbr( + // Add ABBR_OFF for characters above 0x100, this is + // what check_abbr() expects. + (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) : c) + && c != Ctrl_RSB)) + { + insert_special(c, FALSE, FALSE); +#ifdef FEAT_RIGHTLEFT + revins_legal++; + revins_chars++; +#endif + } + + auto_format(FALSE, TRUE); + +#ifdef FEAT_FOLDING + // When inserting a character the cursor line must never be in a + // closed fold. + foldOpenCursor(); +#endif + break; + } // end of switch (c) + + // If typed something may trigger CursorHoldI again. + if (c != K_CURSORHOLD +#ifdef FEAT_COMPL_FUNC + // but not in CTRL-X mode, a script can't restore the state + && ctrl_x_mode_normal() +#endif + ) + did_cursorhold = FALSE; + + // If the cursor was moved we didn't just insert a space + if (arrow_used) + inserted_space = FALSE; + + if (can_cindent && cindent_on() && ctrl_x_mode_normal()) + { +force_cindent: + /* + * Indent now if a key was typed that is in 'cinkeys'. + */ + if (in_cinkeys(c, ' ', line_is_white)) + { + if (stop_arrow() == OK) + // re-indent the current line + do_c_expr_indent(); + } + } + + } // for (;;) + // NOTREACHED +} + + int +ins_need_undo_get(void) +{ + return ins_need_undo; +} + +/* + * Redraw for Insert mode. + * This is postponed until getting the next character to make '$' in the 'cpo' + * option work correctly. + * Only redraw when there are no characters available. This speeds up + * inserting sequences of characters (e.g., for CTRL-R). + */ + void +ins_redraw(int ready) // not busy with something +{ +#ifdef FEAT_CONCEAL + linenr_T conceal_old_cursor_line = 0; + linenr_T conceal_new_cursor_line = 0; + int conceal_update_lines = FALSE; +#endif + + if (char_avail()) + return; + + // Trigger CursorMoved if the cursor moved. Not when the popup menu is + // visible, the command might delete it. + if (ready && (has_cursormovedI() +# ifdef FEAT_PROP_POPUP + || popup_visible +# endif +# if defined(FEAT_CONCEAL) + || curwin->w_p_cole > 0 +# endif + ) + && !EQUAL_POS(last_cursormoved, curwin->w_cursor) + && !pum_visible()) + { +# ifdef FEAT_SYN_HL + // Need to update the screen first, to make sure syntax + // highlighting is correct after making a change (e.g., inserting + // a "(". The autocommand may also require a redraw, so it's done + // again below, unfortunately. + if (syntax_present(curwin) && must_redraw) + update_screen(0); +# endif + if (has_cursormovedI()) + { + // Make sure curswant is correct, an autocommand may call + // getcurpos(). + update_curswant(); + ins_apply_autocmds(EVENT_CURSORMOVEDI); + } +#ifdef FEAT_PROP_POPUP + if (popup_visible) + popup_check_cursor_pos(); +#endif +# ifdef FEAT_CONCEAL + if (curwin->w_p_cole > 0) + { + conceal_old_cursor_line = last_cursormoved.lnum; + conceal_new_cursor_line = curwin->w_cursor.lnum; + conceal_update_lines = TRUE; + } +# endif + last_cursormoved = curwin->w_cursor; + } + + // Trigger TextChangedI if b_changedtick_i differs. + if (ready && has_textchangedI() + && curbuf->b_last_changedtick_i != CHANGEDTICK(curbuf) + && !pum_visible()) + { + aco_save_T aco; + varnumber_T tick = CHANGEDTICK(curbuf); + + // Save and restore curwin and curbuf, in case the autocmd changes + // them. + aucmd_prepbuf(&aco, curbuf); + apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf); + aucmd_restbuf(&aco); + curbuf->b_last_changedtick_i = CHANGEDTICK(curbuf); + if (tick != CHANGEDTICK(curbuf)) // see ins_apply_autocmds() + u_save(curwin->w_cursor.lnum, + (linenr_T)(curwin->w_cursor.lnum + 1)); + } + + // Trigger TextChangedP if b_changedtick_pum differs. When the popupmenu + // closes TextChangedI will need to trigger for backwards compatibility, + // thus use different b_last_changedtick* variables. + if (ready && has_textchangedP() + && curbuf->b_last_changedtick_pum != CHANGEDTICK(curbuf) + && pum_visible()) + { + aco_save_T aco; + varnumber_T tick = CHANGEDTICK(curbuf); + + // Save and restore curwin and curbuf, in case the autocmd changes + // them. + aucmd_prepbuf(&aco, curbuf); + apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, FALSE, curbuf); + aucmd_restbuf(&aco); + curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf); + if (tick != CHANGEDTICK(curbuf)) // see ins_apply_autocmds() + u_save(curwin->w_cursor.lnum, + (linenr_T)(curwin->w_cursor.lnum + 1)); + } + + if (ready) + may_trigger_win_scrolled_resized(); + + // Trigger SafeState if nothing is pending. + may_trigger_safestate(ready + && !ins_compl_active() + && !pum_visible()); + +#if defined(FEAT_CONCEAL) + if ((conceal_update_lines + && (conceal_old_cursor_line != conceal_new_cursor_line + || conceal_cursor_line(curwin))) + || need_cursor_line_redraw) + { + if (conceal_old_cursor_line != conceal_new_cursor_line) + redrawWinline(curwin, conceal_old_cursor_line); + redrawWinline(curwin, conceal_new_cursor_line == 0 + ? curwin->w_cursor.lnum : conceal_new_cursor_line); + curwin->w_valid &= ~VALID_CROW; + need_cursor_line_redraw = FALSE; + } +#endif + if (must_redraw) + update_screen(0); + else if (clear_cmdline || redraw_cmdline) + showmode(); // clear cmdline and show mode + showruler(FALSE); + setcursor(); + emsg_on_display = FALSE; // may remove error message now +} + +/* + * Handle a CTRL-V or CTRL-Q typed in Insert mode. + */ + static void +ins_ctrl_v(void) +{ + int c; + int did_putchar = FALSE; + + // may need to redraw when no more chars available now + ins_redraw(FALSE); + + if (redrawing() && !char_avail()) + { + edit_putchar('^', TRUE); + did_putchar = TRUE; + } + AppendToRedobuff((char_u *)CTRL_V_STR); // CTRL-V + + add_to_showcmd_c(Ctrl_V); + + // Do not change any modifyOtherKeys ESC sequence to a normal key for + // CTRL-SHIFT-V. + c = get_literal(mod_mask & MOD_MASK_SHIFT); + if (did_putchar) + // when the line fits in 'columns' the '^' is at the start of the next + // line and will not removed by the redraw + edit_unputchar(); + clear_showcmd(); + + insert_special(c, FALSE, TRUE); +#ifdef FEAT_RIGHTLEFT + revins_chars++; + revins_legal++; +#endif +} + +/* + * After getting an ESC or CSI for a literal key: If the typeahead buffer + * contains a modifyOtherKeys sequence then decode it and return the result. + * Otherwise return "c". + * Note that this doesn't wait for characters, they must be in the typeahead + * buffer already. + */ + static int +decodeModifyOtherKeys(int c) +{ + char_u *p = typebuf.tb_buf + typebuf.tb_off; + int idx; + int form = 0; + int argidx = 0; + int arg[2] = {0, 0}; + + // Recognize: + // form 0: {lead}{key};{modifier}u + // form 1: {lead}27;{modifier};{key}~ + if (typebuf.tb_len >= 4 && (c == CSI || (c == ESC && *p == '['))) + { + idx = (*p == '['); + if (p[idx] == '2' && p[idx + 1] == '7' && p[idx + 2] == ';') + { + form = 1; + idx += 3; + } + while (idx < typebuf.tb_len && argidx < 2) + { + if (p[idx] == ';') + ++argidx; + else if (VIM_ISDIGIT(p[idx])) + arg[argidx] = arg[argidx] * 10 + (p[idx] - '0'); + else + break; + ++idx; + } + if (idx < typebuf.tb_len + && p[idx] == (form == 1 ? '~' : 'u') + && argidx == 1) + { + // Match, consume the code. + typebuf.tb_off += idx + 1; + typebuf.tb_len -= idx + 1; +#if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL) + if (typebuf.tb_len == 0) + typebuf_was_filled = FALSE; +#endif + + mod_mask = decode_modifiers(arg[!form]); + c = merge_modifyOtherKeys(arg[form], &mod_mask); + } + } + + return c; +} + +/* + * Put a character directly onto the screen. It's not stored in a buffer. + * Used while handling CTRL-K, CTRL-V, etc. in Insert mode. + */ +static int pc_status; +#define PC_STATUS_UNSET 0 // pc_bytes was not set +#define PC_STATUS_RIGHT 1 // right half of double-wide char +#define PC_STATUS_LEFT 2 // left half of double-wide char +#define PC_STATUS_SET 3 // pc_bytes was filled +static char_u pc_bytes[MB_MAXBYTES + 1]; // saved bytes +static int pc_attr; +static int pc_row; +static int pc_col; + + void +edit_putchar(int c, int highlight) +{ + int attr; + + if (ScreenLines == NULL) + return; + + update_topline(); // just in case w_topline isn't valid + validate_cursor(); + if (highlight) + attr = HL_ATTR(HLF_8); + else + attr = 0; + pc_row = W_WINROW(curwin) + curwin->w_wrow; + pc_col = curwin->w_wincol; + pc_status = PC_STATUS_UNSET; +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + { + pc_col += curwin->w_width - 1 - curwin->w_wcol; + if (has_mbyte) + { + int fix_col = mb_fix_col(pc_col, pc_row); + + if (fix_col != pc_col) + { + screen_putchar(' ', pc_row, fix_col, attr); + --curwin->w_wcol; + pc_status = PC_STATUS_RIGHT; + } + } + } + else +#endif + { + pc_col += curwin->w_wcol; + if (mb_lefthalve(pc_row, pc_col)) + pc_status = PC_STATUS_LEFT; + } + + // save the character to be able to put it back + if (pc_status == PC_STATUS_UNSET) + { + screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr); + pc_status = PC_STATUS_SET; + } + screen_putchar(c, pc_row, pc_col, attr); +} + +#if defined(FEAT_JOB_CHANNEL) || defined(PROTO) +/* + * Set the insert start position for when using a prompt buffer. + */ + void +set_insstart(linenr_T lnum, int col) +{ + Insstart.lnum = lnum; + Insstart.col = col; + Insstart_orig = Insstart; + Insstart_textlen = Insstart.col; + Insstart_blank_vcol = MAXCOL; + arrow_used = FALSE; +} +#endif + +/* + * Undo the previous edit_putchar(). + */ + void +edit_unputchar(void) +{ + if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled) + { + if (pc_status == PC_STATUS_RIGHT) + ++curwin->w_wcol; + if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT) + redrawWinline(curwin, curwin->w_cursor.lnum); + else + screen_puts(pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr); + } +} + +/* + * Called when "$" is in 'cpoptions': display a '$' at the end of the changed + * text. Only works when cursor is in the line that changes. + */ + void +display_dollar(colnr_T col_arg) +{ + colnr_T col = col_arg < 0 ? 0 : col_arg; + colnr_T save_col; + + if (!redrawing()) + return; + + cursor_off(); + save_col = curwin->w_cursor.col; + curwin->w_cursor.col = col; + if (has_mbyte) + { + char_u *p; + + // If on the last byte of a multi-byte move to the first byte. + p = ml_get_curline(); + curwin->w_cursor.col -= (*mb_head_off)(p, p + col); + } + curs_columns(FALSE); // recompute w_wrow and w_wcol + if (curwin->w_wcol < curwin->w_width) + { + edit_putchar('$', FALSE); + dollar_vcol = curwin->w_virtcol; + } + curwin->w_cursor.col = save_col; +} + +/* + * Call this function before moving the cursor from the normal insert position + * in insert mode. + */ + void +undisplay_dollar(void) +{ + if (dollar_vcol < 0) + return; + + dollar_vcol = -1; + redrawWinline(curwin, curwin->w_cursor.lnum); +} + +/* + * Truncate the space at the end of a line. This is to be used only in an + * insert mode. It handles fixing the replace stack for MODE_REPLACE and + * MODE_VREPLACE modes. + */ + void +truncate_spaces(char_u *line) +{ + int i; + + // find start of trailing white space + for (i = (int)STRLEN(line) - 1; i >= 0 && VIM_ISWHITE(line[i]); i--) + { + if (State & REPLACE_FLAG) + replace_join(0); // remove a NUL from the replace stack + } + line[i + 1] = NUL; +} + +/* + * Backspace the cursor until the given column. Handles MODE_REPLACE and + * MODE_VREPLACE modes correctly. May also be used when not in insert mode at + * all. Will attempt not to go before "col" even when there is a composing + * character. + */ + void +backspace_until_column(int col) +{ + while ((int)curwin->w_cursor.col > col) + { + curwin->w_cursor.col--; + if (State & REPLACE_FLAG) + replace_do_bs(col); + else if (!del_char_after_col(col)) + break; + } +} + +/* + * Like del_char(), but make sure not to go before column "limit_col". + * Only matters when there are composing characters. + * Return TRUE when something was deleted. + */ + static int +del_char_after_col(int limit_col UNUSED) +{ + if (enc_utf8 && limit_col >= 0) + { + colnr_T ecol = curwin->w_cursor.col + 1; + + // Make sure the cursor is at the start of a character, but + // skip forward again when going too far back because of a + // composing character. + mb_adjust_cursor(); + while (curwin->w_cursor.col < (colnr_T)limit_col) + { + int l = utf_ptr2len(ml_get_cursor()); + + if (l == 0) // end of line + break; + curwin->w_cursor.col += l; + } + if (*ml_get_cursor() == NUL || curwin->w_cursor.col == ecol) + return FALSE; + del_bytes((long)((int)ecol - curwin->w_cursor.col), FALSE, TRUE); + } + else + (void)del_char(FALSE); + return TRUE; +} + +/* + * Next character is interpreted literally. + * A one, two or three digit decimal number is interpreted as its byte value. + * If one or two digits are entered, the next character is given to vungetc(). + * For Unicode a character > 255 may be returned. + * If "noReduceKeys" is TRUE do not change any modifyOtherKeys ESC sequence + * into a normal key, return ESC. + */ + int +get_literal(int noReduceKeys) +{ + int cc; + int nc; + int i; + int hex = FALSE; + int octal = FALSE; + int unicode = 0; + + if (got_int) + return Ctrl_C; + +#ifdef FEAT_GUI + /* + * In GUI there is no point inserting the internal code for a special key. + * It is more useful to insert the string "" instead. This would + * probably be useful in a text window too, but it would not be + * vi-compatible (maybe there should be an option for it?) -- webb + */ + if (gui.in_use) + { + ++allow_keys; + if (noReduceKeys) + ++no_reduce_keys; + } +#endif +#ifdef USE_ON_FLY_SCROLL + dont_scroll = TRUE; // disallow scrolling here +#endif + ++no_mapping; // don't map the next key hits + cc = 0; + i = 0; + for (;;) + { + nc = plain_vgetc(); + if ((nc == ESC || nc == CSI) && !noReduceKeys) + nc = decodeModifyOtherKeys(nc); + + if ((mod_mask & ~MOD_MASK_SHIFT) != 0) + // A character with non-Shift modifiers should not be a valid + // character for i_CTRL-V_digit. + break; + + if ((State & MODE_CMDLINE) == 0 && MB_BYTE2LEN_CHECK(nc) == 1) + add_to_showcmd(nc); + if (nc == 'x' || nc == 'X') + hex = TRUE; + else if (nc == 'o' || nc == 'O') + octal = TRUE; + else if (nc == 'u' || nc == 'U') + unicode = nc; + else + { + if (hex || unicode != 0) + { + if (!vim_isxdigit(nc)) + break; + cc = cc * 16 + hex2nr(nc); + } + else if (octal) + { + if (nc < '0' || nc > '7') + break; + cc = cc * 8 + nc - '0'; + } + else + { + if (!VIM_ISDIGIT(nc)) + break; + cc = cc * 10 + nc - '0'; + } + + ++i; + } + + if (cc > 255 && unicode == 0) + cc = 255; // limit range to 0-255 + nc = 0; + + if (hex) // hex: up to two chars + { + if (i >= 2) + break; + } + else if (unicode) // Unicode: up to four or eight chars + { + if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8)) + break; + } + else if (i >= 3) // decimal or octal: up to three chars + break; + } + if (i == 0) // no number entered + { + if (nc == K_ZERO) // NUL is stored as NL + { + cc = '\n'; + nc = 0; + } + else + { + cc = nc; + nc = 0; + } + } + + if (cc == 0) // NUL is stored as NL + cc = '\n'; + if (enc_dbcs && (cc & 0xff) == 0) + cc = '?'; // don't accept an illegal DBCS char, the NUL in the + // second byte will cause trouble! + + --no_mapping; +#ifdef FEAT_GUI + if (gui.in_use) + { + --allow_keys; + if (noReduceKeys) + --no_reduce_keys; + } +#endif + if (nc) + { + vungetc(nc); + // A character typed with i_CTRL-V_digit cannot have modifiers. + mod_mask = 0; + } + got_int = FALSE; // CTRL-C typed after CTRL-V is not an interrupt + return cc; +} + +/* + * Insert character, taking care of special keys and mod_mask + */ + static void +insert_special( + int c, + int allow_modmask, + int ctrlv) // c was typed after CTRL-V +{ + char_u *p; + int len; + + /* + * Special function key, translate into "". Up to the last '>' is + * inserted with ins_str(), so as not to replace characters in replace + * mode. + * Only use mod_mask for special keys, to avoid things like , + * unless 'allow_modmask' is TRUE. + */ +#ifdef MACOS_X + // Command-key never produces a normal key + if (mod_mask & MOD_MASK_CMD) + allow_modmask = TRUE; +#endif + if (IS_SPECIAL(c) || (mod_mask && allow_modmask)) + { + p = get_special_key_name(c, mod_mask); + len = (int)STRLEN(p); + c = p[len - 1]; + if (len > 2) + { + if (stop_arrow() == FAIL) + return; + p[len - 1] = NUL; + ins_str(p); + AppendToRedobuffLit(p, -1); + ctrlv = FALSE; + } + } + if (stop_arrow() == OK) + insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1); +} + +/* + * Special characters in this context are those that need processing other + * than the simple insertion that can be performed here. This includes ESC + * which terminates the insert, and CR/NL which need special processing to + * open up a new line. This routine tries to optimize insertions performed by + * the "redo", "undo" or "put" commands, so it needs to know when it should + * stop and defer processing to the "normal" mechanism. + * '0' and '^' are special, because they can be followed by CTRL-D. + */ +#define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^') + +/* + * "flags": INSCHAR_FORMAT - force formatting + * INSCHAR_CTRLV - char typed just after CTRL-V + * INSCHAR_NO_FEX - don't use 'formatexpr' + * + * NOTE: passes the flags value straight through to internal_format() which, + * beside INSCHAR_FORMAT (above), is also looking for these: + * INSCHAR_DO_COM - format comments + * INSCHAR_COM_LIST - format comments with num list or 2nd line indent + */ + void +insertchar( + int c, // character to insert or NUL + int flags, // INSCHAR_FORMAT, etc. + int second_indent) // indent for second line if >= 0 +{ + int textwidth; + char_u *p; + int fo_ins_blank; + int force_format = flags & INSCHAR_FORMAT; + + textwidth = comp_textwidth(force_format); + fo_ins_blank = has_format_option(FO_INS_BLANK); + + /* + * Try to break the line in two or more pieces when: + * - Always do this if we have been called to do formatting only. + * - Always do this when 'formatoptions' has the 'a' flag and the line + * ends in white space. + * - Otherwise: + * - Don't do this if inserting a blank + * - Don't do this if an existing character is being replaced, unless + * we're in MODE_VREPLACE state. + * - Do this if the cursor is not on the line where insert started + * or - 'formatoptions' doesn't have 'l' or the line was not too long + * before the insert. + * - 'formatoptions' doesn't have 'b' or a blank was inserted at or + * before 'textwidth' + */ + if (textwidth > 0 + && (force_format + || (!VIM_ISWHITE(c) + && !((State & REPLACE_FLAG) + && !(State & VREPLACE_FLAG) + && *ml_get_cursor() != NUL) + && (curwin->w_cursor.lnum != Insstart.lnum + || ((!has_format_option(FO_INS_LONG) + || Insstart_textlen <= (colnr_T)textwidth) + && (!fo_ins_blank + || Insstart_blank_vcol <= (colnr_T)textwidth + )))))) + { + // Format with 'formatexpr' when it's set. Use internal formatting + // when 'formatexpr' isn't set or it returns non-zero. +#if defined(FEAT_EVAL) + int do_internal = TRUE; + colnr_T virtcol = get_nolist_virtcol() + + char2cells(c != NUL ? c : gchar_cursor()); + + if (*curbuf->b_p_fex != NUL && (flags & INSCHAR_NO_FEX) == 0 + && (force_format || virtcol > (colnr_T)textwidth)) + { + do_internal = (fex_format(curwin->w_cursor.lnum, 1L, c) != 0); + // It may be required to save for undo again, e.g. when setline() + // was called. + ins_need_undo = TRUE; + } + if (do_internal) +#endif + internal_format(textwidth, second_indent, flags, c == NUL, c); + } + + if (c == NUL) // only formatting was wanted + return; + + // Check whether this character should end a comment. + if (did_ai && c == end_comment_pending) + { + char_u *line; + char_u lead_end[COM_MAX_LEN]; // end-comment string + int middle_len, end_len; + int i; + + /* + * Need to remove existing (middle) comment leader and insert end + * comment leader. First, check what comment leader we can find. + */ + i = get_leader_len(line = ml_get_curline(), &p, FALSE, TRUE); + if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) // Just checking + { + // Skip middle-comment string + while (*p && p[-1] != ':') // find end of middle flags + ++p; + middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ","); + // Don't count trailing white space for middle_len + while (middle_len > 0 && VIM_ISWHITE(lead_end[middle_len - 1])) + --middle_len; + + // Find the end-comment string + while (*p && p[-1] != ':') // find end of end flags + ++p; + end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ","); + + // Skip white space before the cursor + i = curwin->w_cursor.col; + while (--i >= 0 && VIM_ISWHITE(line[i])) + ; + i++; + + // Skip to before the middle leader + i -= middle_len; + + // Check some expected things before we go on + if (i >= 0 && lead_end[end_len - 1] == end_comment_pending) + { + // Backspace over all the stuff we want to replace + backspace_until_column(i); + + // Insert the end-comment string, except for the last + // character, which will get inserted as normal later. + ins_bytes_len(lead_end, end_len - 1); + } + } + } + end_comment_pending = NUL; + + did_ai = FALSE; + did_si = FALSE; + can_si = FALSE; + can_si_back = FALSE; + + /* + * If there's any pending input, grab up to INPUT_BUFLEN at once. + * This speeds up normal text input considerably. + * Don't do this when 'cindent' or 'indentexpr' is set, because we might + * need to re-indent at a ':', or any other character (but not what + * 'paste' is set).. + * Don't do this when there an InsertCharPre autocommand is defined, + * because we need to fire the event for every character. + * Do the check for InsertCharPre before the call to vpeekc() because the + * InsertCharPre autocommand could change the input buffer. + */ +#ifdef USE_ON_FLY_SCROLL + dont_scroll = FALSE; // allow scrolling here +#endif + + if ( !ISSPECIAL(c) + && (!has_mbyte || (*mb_char2len)(c) == 1) + && !has_insertcharpre() + && vpeekc() != NUL + && !(State & REPLACE_FLAG) + && !cindent_on() +#ifdef FEAT_RIGHTLEFT + && !p_ri +#endif + ) + { +#define INPUT_BUFLEN 100 + char_u buf[INPUT_BUFLEN + 1]; + int i; + colnr_T virtcol = 0; + + buf[0] = c; + i = 1; + if (textwidth > 0) + virtcol = get_nolist_virtcol(); + /* + * Stop the string when: + * - no more chars available + * - finding a special character (command key) + * - buffer is full + * - running into the 'textwidth' boundary + * - need to check for abbreviation: A non-word char after a word-char + */ + while ( (c = vpeekc()) != NUL + && !ISSPECIAL(c) + && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1) + && i < INPUT_BUFLEN + && (textwidth == 0 + || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth) + && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1]))) + { +#ifdef FEAT_RIGHTLEFT + c = vgetc(); + if (p_hkmap && KeyTyped) + c = hkmap(c); // Hebrew mode mapping + buf[i++] = c; +#else + buf[i++] = vgetc(); +#endif + } + +#ifdef FEAT_DIGRAPHS + do_digraph(-1); // clear digraphs + do_digraph(buf[i-1]); // may be the start of a digraph +#endif + buf[i] = NUL; + ins_str(buf); + if (flags & INSCHAR_CTRLV) + { + redo_literal(*buf); + i = 1; + } + else + i = 0; + if (buf[i] != NUL) + AppendToRedobuffLit(buf + i, -1); + } + else + { + int cc; + + if (has_mbyte && (cc = (*mb_char2len)(c)) > 1) + { + char_u buf[MB_MAXBYTES + 1]; + + (*mb_char2bytes)(c, buf); + buf[cc] = NUL; + ins_char_bytes(buf, cc); + AppendCharToRedobuff(c); + } + else + { + ins_char(c); + if (flags & INSCHAR_CTRLV) + redo_literal(c); + else + AppendCharToRedobuff(c); + } + } +} + +/* + * Put a character in the redo buffer, for when just after a CTRL-V. + */ + static void +redo_literal(int c) +{ + char_u buf[10]; + + // Only digits need special treatment. Translate them into a string of + // three digits. + if (VIM_ISDIGIT(c)) + { + vim_snprintf((char *)buf, sizeof(buf), "%03d", c); + AppendToRedobuff(buf); + } + else + AppendCharToRedobuff(c); +} + +/* + * start_arrow() is called when an arrow key is used in insert mode. + * For undo/redo it resembles hitting the key. + */ + void +start_arrow( + pos_T *end_insert_pos) // can be NULL +{ + start_arrow_common(end_insert_pos, TRUE); +} + +/* + * Like start_arrow() but with end_change argument. + * Will prepare for redo of CTRL-G U if "end_change" is FALSE. + */ + static void +start_arrow_with_change( + pos_T *end_insert_pos, // can be NULL + int end_change) // end undoable change +{ + start_arrow_common(end_insert_pos, end_change); + if (!end_change) + { + AppendCharToRedobuff(Ctrl_G); + AppendCharToRedobuff('U'); + } +} + + static void +start_arrow_common( + pos_T *end_insert_pos, // can be NULL + int end_change) // end undoable change +{ + if (!arrow_used && end_change) // something has been inserted + { + AppendToRedobuff(ESC_STR); + stop_insert(end_insert_pos, FALSE, FALSE); + arrow_used = TRUE; // this means we stopped the current insert + } +#ifdef FEAT_SPELL + check_spell_redraw(); +#endif +} + +#ifdef FEAT_SPELL +/* + * If we skipped highlighting word at cursor, do it now. + * It may be skipped again, thus reset spell_redraw_lnum first. + */ + static void +check_spell_redraw(void) +{ + if (spell_redraw_lnum != 0) + { + linenr_T lnum = spell_redraw_lnum; + + spell_redraw_lnum = 0; + redrawWinline(curwin, lnum); + } +} + +#endif + +/* + * stop_arrow() is called before a change is made in insert mode. + * If an arrow key has been used, start a new insertion. + * Returns FAIL if undo is impossible, shouldn't insert then. + */ + int +stop_arrow(void) +{ + if (arrow_used) + { + Insstart = curwin->w_cursor; // new insertion starts here + if (Insstart.col > Insstart_orig.col && !ins_need_undo) + // Don't update the original insert position when moved to the + // right, except when nothing was inserted yet. + update_Insstart_orig = FALSE; + Insstart_textlen = (colnr_T)linetabsize_str(ml_get_curline()); + + if (u_save_cursor() == OK) + { + arrow_used = FALSE; + ins_need_undo = FALSE; + } + + ai_col = 0; + if (State & VREPLACE_FLAG) + { + orig_line_count = curbuf->b_ml.ml_line_count; + vr_lines_changed = 1; + } + ResetRedobuff(); + AppendToRedobuff((char_u *)"1i"); // pretend we start an insertion + new_insert_skip = 2; + } + else if (ins_need_undo) + { + if (u_save_cursor() == OK) + ins_need_undo = FALSE; + } + +#ifdef FEAT_FOLDING + // Always open fold at the cursor line when inserting something. + foldOpenCursor(); +#endif + + return (arrow_used || ins_need_undo ? FAIL : OK); +} + +/* + * Do a few things to stop inserting. + * "end_insert_pos" is where insert ended. It is NULL when we already jumped + * to another window/buffer. + */ + static void +stop_insert( + pos_T *end_insert_pos, + int esc, // called by ins_esc() + int nomove) // , don't move cursor +{ + int cc; + char_u *ptr; + + stop_redo_ins(); + replace_flush(); // abandon replace stack + + /* + * Save the inserted text for later redo with ^@ and CTRL-A. + * Don't do it when "restart_edit" was set and nothing was inserted, + * otherwise CTRL-O w and then will clear "last_insert". + */ + ptr = get_inserted(); + if (did_restart_edit == 0 || (ptr != NULL + && (int)STRLEN(ptr) > new_insert_skip)) + { + vim_free(last_insert); + last_insert = ptr; + last_insert_skip = new_insert_skip; + } + else + vim_free(ptr); + + if (!arrow_used && end_insert_pos != NULL) + { + // Auto-format now. It may seem strange to do this when stopping an + // insertion (or moving the cursor), but it's required when appending + // a line and having it end in a space. But only do it when something + // was actually inserted, otherwise undo won't work. + if (!ins_need_undo && has_format_option(FO_AUTO)) + { + pos_T tpos = curwin->w_cursor; + + // When the cursor is at the end of the line after a space the + // formatting will move it to the following word. Avoid that by + // moving the cursor onto the space. + cc = 'x'; + if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL) + { + dec_cursor(); + cc = gchar_cursor(); + if (!VIM_ISWHITE(cc)) + curwin->w_cursor = tpos; + } + + auto_format(TRUE, FALSE); + + if (VIM_ISWHITE(cc)) + { + if (gchar_cursor() != NUL) + inc_cursor(); + // If the cursor is still at the same character, also keep + // the "coladd". + if (gchar_cursor() == NUL + && curwin->w_cursor.lnum == tpos.lnum + && curwin->w_cursor.col == tpos.col) + curwin->w_cursor.coladd = tpos.coladd; + } + } + + // If a space was inserted for auto-formatting, remove it now. + check_auto_format(TRUE); + + // If we just did an auto-indent, remove the white space from the end + // of the line, and put the cursor back. + // Do this when ESC was used or moving the cursor up/down. + // Check for the old position still being valid, just in case the text + // got changed unexpectedly. + if (!nomove && did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL + && curwin->w_cursor.lnum != end_insert_pos->lnum)) + && end_insert_pos->lnum <= curbuf->b_ml.ml_line_count) + { + pos_T tpos = curwin->w_cursor; + + curwin->w_cursor = *end_insert_pos; + check_cursor_col(); // make sure it is not past the line + for (;;) + { + if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) + --curwin->w_cursor.col; + cc = gchar_cursor(); + if (!VIM_ISWHITE(cc)) + break; + if (del_char(TRUE) == FAIL) + break; // should not happen + } + if (curwin->w_cursor.lnum != tpos.lnum) + curwin->w_cursor = tpos; + else + { + // reset tpos, could have been invalidated in the loop above + tpos = curwin->w_cursor; + tpos.col++; + if (cc != NUL && gchar_pos(&tpos) == NUL) + ++curwin->w_cursor.col; // put cursor back on the NUL + } + + // may have started Visual mode, adjust the position for + // deleted characters. + if (VIsual_active) + check_visual_pos(); + } + } + did_ai = FALSE; + did_si = FALSE; + can_si = FALSE; + can_si_back = FALSE; + + // Set '[ and '] to the inserted text. When end_insert_pos is NULL we are + // now in a different buffer. + if (end_insert_pos != NULL) + { + curbuf->b_op_start = Insstart; + curbuf->b_op_start_orig = Insstart_orig; + curbuf->b_op_end = *end_insert_pos; + } +} + +/* + * Set the last inserted text to a single character. + * Used for the replace command. + */ + void +set_last_insert(int c) +{ + char_u *s; + + vim_free(last_insert); + last_insert = alloc(MB_MAXBYTES * 3 + 5); + if (last_insert == NULL) + return; + + s = last_insert; + // Use the CTRL-V only when entering a special char + if (c < ' ' || c == DEL) + *s++ = Ctrl_V; + s = add_char2buf(c, s); + *s++ = ESC; + *s++ = NUL; + last_insert_skip = 0; +} + +#if defined(EXITFREE) || defined(PROTO) + void +free_last_insert(void) +{ + VIM_CLEAR(last_insert); +} +#endif + +/* + * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL + * and CSI. Handle multi-byte characters. + * Returns a pointer to after the added bytes. + */ + char_u * +add_char2buf(int c, char_u *s) +{ + char_u temp[MB_MAXBYTES + 1]; + int i; + int len; + + len = (*mb_char2bytes)(c, temp); + for (i = 0; i < len; ++i) + { + c = temp[i]; + // Need to escape K_SPECIAL and CSI like in the typeahead buffer. + if (c == K_SPECIAL) + { + *s++ = K_SPECIAL; + *s++ = KS_SPECIAL; + *s++ = KE_FILLER; + } +#ifdef FEAT_GUI + else if (c == CSI) + { + *s++ = CSI; + *s++ = KS_EXTRA; + *s++ = (int)KE_CSI; + } +#endif + else + *s++ = c; + } + return s; +} + +/* + * move cursor to start of line + * if flags & BL_WHITE move to first non-white + * if flags & BL_SOL move to first non-white if startofline is set, + * otherwise keep "curswant" column + * if flags & BL_FIX don't leave the cursor on a NUL. + */ + void +beginline(int flags) +{ + if ((flags & BL_SOL) && !p_sol) + coladvance(curwin->w_curswant); + else + { + curwin->w_cursor.col = 0; + curwin->w_cursor.coladd = 0; + + if (flags & (BL_WHITE | BL_SOL)) + { + char_u *ptr; + + for (ptr = ml_get_curline(); VIM_ISWHITE(*ptr) + && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr) + ++curwin->w_cursor.col; + } + curwin->w_set_curswant = TRUE; + } + adjust_skipcol(); +} + +/* + * oneright oneleft cursor_down cursor_up + * + * Move one char {right,left,down,up}. + * Doesn't move onto the NUL past the end of the line, unless it is allowed. + * Return OK when successful, FAIL when we hit a line of file boundary. + */ + + int +oneright(void) +{ + char_u *ptr; + int l; + + if (virtual_active()) + { + pos_T prevpos = curwin->w_cursor; + + // Adjust for multi-wide char (excluding TAB) + ptr = ml_get_cursor(); + coladvance(getviscol() + ((*ptr != TAB + && vim_isprintc((*mb_ptr2char)(ptr))) + ? ptr2cells(ptr) : 1)); + curwin->w_set_curswant = TRUE; + // Return OK if the cursor moved, FAIL otherwise (at window edge). + return (prevpos.col != curwin->w_cursor.col + || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL; + } + + ptr = ml_get_cursor(); + if (*ptr == NUL) + return FAIL; // already at the very end + + if (has_mbyte) + l = (*mb_ptr2len)(ptr); + else + l = 1; + + // move "l" bytes right, but don't end up on the NUL, unless 'virtualedit' + // contains "onemore". + if (ptr[l] == NUL && (get_ve_flags() & VE_ONEMORE) == 0) + return FAIL; + curwin->w_cursor.col += l; + + curwin->w_set_curswant = TRUE; + adjust_skipcol(); + return OK; +} + + int +oneleft(void) +{ + if (virtual_active()) + { +#ifdef FEAT_LINEBREAK + int width; +#endif + int v = getviscol(); + + if (v == 0) + return FAIL; + +#ifdef FEAT_LINEBREAK + // We might get stuck on 'showbreak', skip over it. + width = 1; + for (;;) + { + coladvance(v - width); + // getviscol() is slow, skip it when 'showbreak' is empty, + // 'breakindent' is not set and there are no multi-byte + // characters + if ((*get_showbreak_value(curwin) == NUL && !curwin->w_p_bri + && !has_mbyte) || getviscol() < v) + break; + ++width; + } +#else + coladvance(v - 1); +#endif + + if (curwin->w_cursor.coladd == 1) + { + char_u *ptr; + + // Adjust for multi-wide char (not a TAB) + ptr = ml_get_cursor(); + if (*ptr != TAB && vim_isprintc((*mb_ptr2char)(ptr)) + && ptr2cells(ptr) > 1) + curwin->w_cursor.coladd = 0; + } + + curwin->w_set_curswant = TRUE; + return OK; + } + + if (curwin->w_cursor.col == 0) + return FAIL; + + curwin->w_set_curswant = TRUE; + --curwin->w_cursor.col; + + // if the character on the left of the current cursor is a multi-byte + // character, move to its first byte + if (has_mbyte) + mb_adjust_cursor(); + adjust_skipcol(); + return OK; +} + +/* + * Move the cursor up "n" lines in window "wp". + * Takes care of closed folds. + * Returns the new cursor line or zero for failure. + */ + linenr_T +cursor_up_inner(win_T *wp, long n) +{ + linenr_T lnum = wp->w_cursor.lnum; + + // This fails if the cursor is already in the first line or the count is + // larger than the line number and '-' is in 'cpoptions' + if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL)) + return 0; + if (n >= lnum) + lnum = 1; + else +#ifdef FEAT_FOLDING + if (hasAnyFolding(wp)) + { + /* + * Count each sequence of folded lines as one logical line. + */ + // go to the start of the current fold + (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL); + + while (n--) + { + // move up one line + --lnum; + if (lnum <= 1) + break; + // If we entered a fold, move to the beginning, unless in + // Insert mode or when 'foldopen' contains "all": it will open + // in a moment. + if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL))) + (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL); + } + if (lnum < 1) + lnum = 1; + } + else +#endif + lnum -= n; + + wp->w_cursor.lnum = lnum; + return lnum; +} + + int +cursor_up( + long n, + int upd_topline) // When TRUE: update topline +{ + if (n > 0 && cursor_up_inner(curwin, n) == 0) + return FAIL; + + // try to advance to the column we want to be at + coladvance(curwin->w_curswant); + + if (upd_topline) + update_topline(); // make sure curwin->w_topline is valid + + return OK; +} + +/* + * Move the cursor down "n" lines in window "wp". + * Takes care of closed folds. + * Returns the new cursor line or zero for failure. + */ + linenr_T +cursor_down_inner(win_T *wp, long n) +{ + linenr_T lnum = wp->w_cursor.lnum; + linenr_T line_count = wp->w_buffer->b_ml.ml_line_count; + +#ifdef FEAT_FOLDING + // Move to last line of fold, will fail if it's the end-of-file. + (void)hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL); +#endif + // This fails if the cursor is already in the last line or would move + // beyond the last line and '-' is in 'cpoptions' + if (lnum >= line_count + || (lnum + n > line_count && vim_strchr(p_cpo, CPO_MINUS) != NULL)) + return FAIL; + if (lnum + n >= line_count) + lnum = line_count; + else +#ifdef FEAT_FOLDING + if (hasAnyFolding(wp)) + { + linenr_T last; + + // count each sequence of folded lines as one logical line + while (n--) + { + if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL)) + lnum = last + 1; + else + ++lnum; + if (lnum >= line_count) + break; + } + if (lnum > line_count) + lnum = line_count; + } + else +#endif + lnum += n; + + wp->w_cursor.lnum = lnum; + return lnum; +} + +/* + * Cursor down a number of logical lines. + */ + int +cursor_down( + long n, + int upd_topline) // When TRUE: update topline +{ + if (n > 0 && cursor_down_inner(curwin, n) == 0) + return FAIL; + + // try to advance to the column we want to be at + coladvance(curwin->w_curswant); + + if (upd_topline) + update_topline(); // make sure curwin->w_topline is valid + + return OK; +} + +/* + * Stuff the last inserted text in the read buffer. + * Last_insert actually is a copy of the redo buffer, so we + * first have to remove the command. + */ + int +stuff_inserted( + int c, // Command character to be inserted + long count, // Repeat this many times + int no_esc) // Don't add an ESC at the end +{ + char_u *esc_ptr; + char_u *ptr; + char_u *last_ptr; + char_u last = NUL; + + ptr = get_last_insert(); + if (ptr == NULL) + { + emsg(_(e_no_inserted_text_yet)); + return FAIL; + } + + // may want to stuff the command character, to start Insert mode + if (c != NUL) + stuffcharReadbuff(c); + if ((esc_ptr = vim_strrchr(ptr, ESC)) != NULL) + *esc_ptr = NUL; // remove the ESC + + // when the last char is either "0" or "^" it will be quoted if no ESC + // comes after it OR if it will inserted more than once and "ptr" + // starts with ^D. -- Acevedo + last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1; + if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^') + && (no_esc || (*ptr == Ctrl_D && count > 1))) + { + last = *last_ptr; + *last_ptr = NUL; + } + + do + { + stuffReadbuff(ptr); + // a trailing "0" is inserted as "048", "^" as "^" + if (last) + stuffReadbuff( + (char_u *)(last == '0' ? "\026\060\064\070" : "\026^")); + } + while (--count > 0); + + if (last) + *last_ptr = last; + + if (esc_ptr != NULL) + *esc_ptr = ESC; // put the ESC back + + // may want to stuff a trailing ESC, to get out of Insert mode + if (!no_esc) + stuffcharReadbuff(ESC); + + return OK; +} + + char_u * +get_last_insert(void) +{ + if (last_insert == NULL) + return NULL; + return last_insert + last_insert_skip; +} + +/* + * Get last inserted string, and remove trailing . + * Returns pointer to allocated memory (must be freed) or NULL. + */ + char_u * +get_last_insert_save(void) +{ + char_u *s; + int len; + + if (last_insert == NULL) + return NULL; + s = vim_strsave(last_insert + last_insert_skip); + if (s == NULL) + return NULL; + + len = (int)STRLEN(s); + if (len > 0 && s[len - 1] == ESC) // remove trailing ESC + s[len - 1] = NUL; + return s; +} + +/* + * Check the word in front of the cursor for an abbreviation. + * Called when the non-id character "c" has been entered. + * When an abbreviation is recognized it is removed from the text and + * the replacement string is inserted in typebuf.tb_buf[], followed by "c". + */ + static int +echeck_abbr(int c) +{ + // Don't check for abbreviation in paste mode, when disabled and just + // after moving around with cursor keys. + if (p_paste || no_abbr || arrow_used) + return FALSE; + + return check_abbr(c, ml_get_curline(), curwin->w_cursor.col, + curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0); +} + +/* + * replace-stack functions + * + * When replacing characters, the replaced characters are remembered for each + * new character. This is used to re-insert the old text when backspacing. + * + * There is a NUL headed list of characters for each character that is + * currently in the file after the insertion point. When BS is used, one NUL + * headed list is put back for the deleted character. + * + * For a newline, there are two NUL headed lists. One contains the characters + * that the NL replaced. The extra one stores the characters after the cursor + * that were deleted (always white space). + * + * Replace_offset is normally 0, in which case replace_push will add a new + * character at the end of the stack. If replace_offset is not 0, that many + * characters will be left on the stack above the newly inserted character. + */ + +static char_u *replace_stack = NULL; +static long replace_stack_nr = 0; // next entry in replace stack +static long replace_stack_len = 0; // max. number of entries + + void +replace_push( + int c) // character that is replaced (NUL is none) +{ + char_u *p; + + if (replace_stack_nr < replace_offset) // nothing to do + return; + if (replace_stack_len <= replace_stack_nr) + { + replace_stack_len += 50; + p = ALLOC_MULT(char_u, replace_stack_len); + if (p == NULL) // out of memory + { + replace_stack_len -= 50; + return; + } + if (replace_stack != NULL) + { + mch_memmove(p, replace_stack, + (size_t)(replace_stack_nr * sizeof(char_u))); + vim_free(replace_stack); + } + replace_stack = p; + } + p = replace_stack + replace_stack_nr - replace_offset; + if (replace_offset) + mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u))); + *p = c; + ++replace_stack_nr; +} + +/* + * Push a character onto the replace stack. Handles a multi-byte character in + * reverse byte order, so that the first byte is popped off first. + * Return the number of bytes done (includes composing characters). + */ + int +replace_push_mb(char_u *p) +{ + int l = (*mb_ptr2len)(p); + int j; + + for (j = l - 1; j >= 0; --j) + replace_push(p[j]); + return l; +} + +/* + * Pop one item from the replace stack. + * return -1 if stack empty + * return replaced character or NUL otherwise + */ + static int +replace_pop(void) +{ + if (replace_stack_nr == 0) + return -1; + return (int)replace_stack[--replace_stack_nr]; +} + +/* + * Join the top two items on the replace stack. This removes to "off"'th NUL + * encountered. + */ + void +replace_join( + int off) // offset for which NUL to remove +{ + int i; + + for (i = replace_stack_nr; --i >= 0; ) + if (replace_stack[i] == NUL && off-- <= 0) + { + --replace_stack_nr; + mch_memmove(replace_stack + i, replace_stack + i + 1, + (size_t)(replace_stack_nr - i)); + return; + } +} + +/* + * Pop bytes from the replace stack until a NUL is found, and insert them + * before the cursor. Can only be used in MODE_REPLACE or MODE_VREPLACE state. + */ + static void +replace_pop_ins(void) +{ + int cc; + int oldState = State; + + State = MODE_NORMAL; // don't want MODE_REPLACE here + while ((cc = replace_pop()) > 0) + { + mb_replace_pop_ins(cc); + dec_cursor(); + } + State = oldState; +} + +/* + * Insert bytes popped from the replace stack. "cc" is the first byte. If it + * indicates a multi-byte char, pop the other bytes too. + */ + static void +mb_replace_pop_ins(int cc) +{ + int n; + char_u buf[MB_MAXBYTES + 1]; + int i; + int c; + + if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1) + { + buf[0] = cc; + for (i = 1; i < n; ++i) + buf[i] = replace_pop(); + ins_bytes_len(buf, n); + } + else + ins_char(cc); + + if (enc_utf8) + // Handle composing chars. + for (;;) + { + c = replace_pop(); + if (c == -1) // stack empty + break; + if ((n = MB_BYTE2LEN(c)) == 1) + { + // Not a multi-byte char, put it back. + replace_push(c); + break; + } + + buf[0] = c; + for (i = 1; i < n; ++i) + buf[i] = replace_pop(); + if (utf_iscomposing(utf_ptr2char(buf))) + ins_bytes_len(buf, n); + else + { + // Not a composing char, put it back. + for (i = n - 1; i >= 0; --i) + replace_push(buf[i]); + break; + } + + } +} + +/* + * make the replace stack empty + * (called when exiting replace mode) + */ + static void +replace_flush(void) +{ + VIM_CLEAR(replace_stack); + replace_stack_len = 0; + replace_stack_nr = 0; +} + +/* + * Handle doing a BS for one character. + * cc < 0: replace stack empty, just move cursor + * cc == 0: character was inserted, delete it + * cc > 0: character was replaced, put cc (first byte of original char) back + * and check for more characters to be put back + * When "limit_col" is >= 0, don't delete before this column. Matters when + * using composing characters, use del_char_after_col() instead of del_char(). + */ + static void +replace_do_bs(int limit_col) +{ + int cc; + int orig_len = 0; + int ins_len; + int orig_vcols = 0; + colnr_T start_vcol; + char_u *p; + int i; + int vcol; + + cc = replace_pop(); + if (cc > 0) + { +#ifdef FEAT_PROP_POPUP + size_t len_before = 0; // init to shut up GCC + + if (curbuf->b_has_textprop) + { + // Do not adjust text properties for individual delete and insert + // operations, do it afterwards on the resulting text. + len_before = STRLEN(ml_get_curline()); + ++text_prop_frozen; + } +#endif + if (State & VREPLACE_FLAG) + { + // Get the number of screen cells used by the character we are + // going to delete. + getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL); + orig_vcols = chartabsize(ml_get_cursor(), start_vcol); + } + if (has_mbyte) + { + (void)del_char_after_col(limit_col); + if (State & VREPLACE_FLAG) + orig_len = (int)STRLEN(ml_get_cursor()); + replace_push(cc); + } + else + { + pchar_cursor(cc); + if (State & VREPLACE_FLAG) + orig_len = (int)STRLEN(ml_get_cursor()) - 1; + } + replace_pop_ins(); + + if (State & VREPLACE_FLAG) + { + // Get the number of screen cells used by the inserted characters + p = ml_get_cursor(); + ins_len = (int)STRLEN(p) - orig_len; + vcol = start_vcol; + for (i = 0; i < ins_len; ++i) + { + vcol += chartabsize(p + i, vcol); + i += (*mb_ptr2len)(p) - 1; + } + vcol -= start_vcol; + + // Delete spaces that were inserted after the cursor to keep the + // text aligned. + curwin->w_cursor.col += ins_len; + while (vcol > orig_vcols && gchar_cursor() == ' ') + { + del_char(FALSE); + ++orig_vcols; + } + curwin->w_cursor.col -= ins_len; + } + + // mark the buffer as changed and prepare for displaying + changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); + +#ifdef FEAT_PROP_POPUP + if (curbuf->b_has_textprop) + { + size_t len_now = STRLEN(ml_get_curline()); + + --text_prop_frozen; + adjust_prop_columns(curwin->w_cursor.lnum, curwin->w_cursor.col, + (int)(len_now - len_before), 0); + } +#endif + } + else if (cc == 0) + (void)del_char_after_col(limit_col); +} + +#if defined(FEAT_RIGHTLEFT) || defined(PROTO) +/* + * Map Hebrew keyboard when in hkmap mode. + */ + int +hkmap(int c) +{ + if (p_hkmapp) // phonetic mapping, by Ilya Dogolazky + { + enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD, + KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN, + PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV}; + static char_u map[26] = + {(char_u)hALEF/*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/, + (char_u)DALET/*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit/*f*/, + (char_u)GIMEL/*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/, + (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/, + (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/, + (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/, + (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/, + (char_u)VAV /*v*/, (char_u)hSHIN/*w*/, (char_u)-1 /*x*/, + (char_u)AIN /*y*/, (char_u)ZADI /*z*/}; + + if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z') + return (int)(map[CharOrd(c)] - 1 + p_aleph); + // '-1'='sofit' + else if (c == 'x') + return 'X'; + else if (c == 'q') + return '\''; // {geresh}={'} + else if (c == 246) + return ' '; // \"o --> ' ' for a german keyboard + else if (c == 228) + return ' '; // \"a --> ' ' -- / -- + else if (c == 252) + return ' '; // \"u --> ' ' -- / -- + // NOTE: islower() does not do the right thing for us on Linux so we + // do this the same was as 5.7 and previous, so it works correctly on + // all systems. Specifically, the e.g. Delete and Arrow keys are + // munged and won't work if e.g. searching for Hebrew text. + else if (c >= 'a' && c <= 'z') + return (int)(map[CharOrdLow(c)] + p_aleph); + else + return c; + } + else + { + switch (c) + { + case '`': return ';'; + case '/': return '.'; + case '\'': return ','; + case 'q': return '/'; + case 'w': return '\''; + + // Hebrew letters - set offset from 'a' + case ',': c = '{'; break; + case '.': c = 'v'; break; + case ';': c = 't'; break; + default: { + static char str[] = "zqbcxlsjphmkwonu ydafe rig"; + + if (c < 'a' || c > 'z') + return c; + c = str[CharOrdLow(c)]; + break; + } + } + + return (int)(CharOrdLow(c) + p_aleph); + } +} +#endif + + static void +ins_reg(void) +{ + int need_redraw = FALSE; + int regname; + int literally = 0; + int vis_active = VIsual_active; + + /* + * If we are going to wait for a character, show a '"'. + */ + pc_status = PC_STATUS_UNSET; + if (redrawing() && !char_avail()) + { + // may need to redraw when no more chars available now + ins_redraw(FALSE); + + edit_putchar('"', TRUE); + add_to_showcmd_c(Ctrl_R); + } + +#ifdef USE_ON_FLY_SCROLL + dont_scroll = TRUE; // disallow scrolling here +#endif + + /* + * Don't map the register name. This also prevents the mode message to be + * deleted when ESC is hit. + */ + ++no_mapping; + ++allow_keys; + regname = plain_vgetc(); + LANGMAP_ADJUST(regname, TRUE); + if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P) + { + // Get a third key for literal register insertion + literally = regname; + add_to_showcmd_c(literally); + regname = plain_vgetc(); + LANGMAP_ADJUST(regname, TRUE); + } + --no_mapping; + --allow_keys; + +#ifdef FEAT_EVAL + // Don't call u_sync() while typing the expression or giving an error + // message for it. Only call it explicitly. + ++no_u_sync; + if (regname == '=') + { + pos_T curpos = curwin->w_cursor; +# ifdef HAVE_INPUT_METHOD + int im_on = im_get_status(); +# endif + // Sync undo when evaluating the expression calls setline() or + // append(), so that it can be undone separately. + u_sync_once = 2; + + regname = get_expr_register(); + + // Cursor may be moved back a column. + curwin->w_cursor = curpos; + check_cursor(); +# ifdef HAVE_INPUT_METHOD + // Restore the Input Method. + if (im_on) + im_set_active(TRUE); +# endif + } + if (regname == NUL || !valid_yank_reg(regname, FALSE)) + { + vim_beep(BO_REG); + need_redraw = TRUE; // remove the '"' + } + else + { +#endif + if (literally == Ctrl_O || literally == Ctrl_P) + { + // Append the command to the redo buffer. + AppendCharToRedobuff(Ctrl_R); + AppendCharToRedobuff(literally); + AppendCharToRedobuff(regname); + + do_put(regname, NULL, BACKWARD, 1L, + (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND); + } + else if (insert_reg(regname, literally) == FAIL) + { + vim_beep(BO_REG); + need_redraw = TRUE; // remove the '"' + } + else if (stop_insert_mode) + // When the '=' register was used and a function was invoked that + // did ":stopinsert" then stuff_empty() returns FALSE but we won't + // insert anything, need to remove the '"' + need_redraw = TRUE; + +#ifdef FEAT_EVAL + } + --no_u_sync; + if (u_sync_once == 1) + ins_need_undo = TRUE; + u_sync_once = 0; +#endif + clear_showcmd(); + + // If the inserted register is empty, we need to remove the '"' + if (need_redraw || stuff_empty()) + edit_unputchar(); + + // Disallow starting Visual mode here, would get a weird mode. + if (!vis_active && VIsual_active) + end_visual_mode(); +} + +/* + * CTRL-G commands in Insert mode. + */ + static void +ins_ctrl_g(void) +{ + int c; + + // Right after CTRL-X the cursor will be after the ruler. + setcursor(); + + /* + * Don't map the second key. This also prevents the mode message to be + * deleted when ESC is hit. + */ + ++no_mapping; + ++allow_keys; + c = plain_vgetc(); + --no_mapping; + --allow_keys; + switch (c) + { + // CTRL-G k and CTRL-G : cursor up to Insstart.col + case K_UP: + case Ctrl_K: + case 'k': ins_up(TRUE); + break; + + // CTRL-G j and CTRL-G : cursor down to Insstart.col + case K_DOWN: + case Ctrl_J: + case 'j': ins_down(TRUE); + break; + + // CTRL-G u: start new undoable edit + case 'u': u_sync(TRUE); + ins_need_undo = TRUE; + + // Need to reset Insstart, esp. because a BS that joins + // a line to the previous one must save for undo. + update_Insstart_orig = FALSE; + Insstart = curwin->w_cursor; + break; + + // CTRL-G U: do not break undo with the next char + case 'U': + // Allow one left/right cursor movement with the next char, + // without breaking undo. + dont_sync_undo = MAYBE; + break; + + case ESC: + // Esc after CTRL-G cancels it. + break; + + // Unknown CTRL-G command, reserved for future expansion. + default: vim_beep(BO_CTRLG); + } +} + +/* + * CTRL-^ in Insert mode. + */ + static void +ins_ctrl_hat(void) +{ + if (map_to_exists_mode((char_u *)"", MODE_LANGMAP, FALSE)) + { + // ":lmap" mappings exists, Toggle use of ":lmap" mappings. + if (State & MODE_LANGMAP) + { + curbuf->b_p_iminsert = B_IMODE_NONE; + State &= ~MODE_LANGMAP; + } + else + { + curbuf->b_p_iminsert = B_IMODE_LMAP; + State |= MODE_LANGMAP; +#ifdef HAVE_INPUT_METHOD + im_set_active(FALSE); +#endif + } + } +#ifdef HAVE_INPUT_METHOD + else + { + // There are no ":lmap" mappings, toggle IM + if (im_get_status()) + { + curbuf->b_p_iminsert = B_IMODE_NONE; + im_set_active(FALSE); + } + else + { + curbuf->b_p_iminsert = B_IMODE_IM; + State &= ~MODE_LANGMAP; + im_set_active(TRUE); + } + } +#endif + set_iminsert_global(); + showmode(); +#ifdef FEAT_GUI + // may show different cursor shape or color + if (gui.in_use) + gui_update_cursor(TRUE, FALSE); +#endif +#if defined(FEAT_KEYMAP) + // Show/unshow value of 'keymap' in status lines. + status_redraw_curbuf(); +#endif +} + +/* + * Handle ESC in insert mode. + * Returns TRUE when leaving insert mode, FALSE when going to repeat the + * insert. + */ + static int +ins_esc( + long *count, + int cmdchar, + int nomove) // don't move cursor +{ + int temp; + static int disabled_redraw = FALSE; +#ifdef FEAT_CONCEAL + // Remember if the cursor line was concealed before changing State. + int cursor_line_was_concealed = curwin->w_p_cole > 0 + && conceal_cursor_line(curwin); +#endif + +#ifdef FEAT_SPELL + check_spell_redraw(); +#endif + + temp = curwin->w_cursor.col; + if (disabled_redraw) + { + --RedrawingDisabled; + disabled_redraw = FALSE; + } + if (!arrow_used) + { + /* + * Don't append the ESC for "r" and "grx". + * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for + * when "count" is non-zero. + */ + if (cmdchar != 'r' && cmdchar != 'v') + AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR); + + /* + * Repeating insert may take a long time. Check for + * interrupt now and then. + */ + if (*count > 0) + { + line_breakcheck(); + if (got_int) + *count = 0; + } + + if (--*count > 0) // repeat what was typed + { + // Vi repeats the insert without replacing characters. + if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL) + State &= ~REPLACE_FLAG; + + (void)start_redo_ins(); + if (cmdchar == 'r' || cmdchar == 'v') + stuffRedoReadbuff(ESC_STR); // no ESC in redo buffer + ++RedrawingDisabled; + disabled_redraw = TRUE; + return FALSE; // repeat the insert + } + stop_insert(&curwin->w_cursor, TRUE, nomove); + undisplay_dollar(); + } + + if (cmdchar != 'r' && cmdchar != 'v') + ins_apply_autocmds(EVENT_INSERTLEAVEPRE); + + // When an autoindent was removed, curswant stays after the + // indent + if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col) + curwin->w_set_curswant = TRUE; + + // Remember the last Insert position in the '^ mark. + if ((cmdmod.cmod_flags & CMOD_KEEPJUMPS) == 0) + curbuf->b_last_insert = curwin->w_cursor; + + /* + * The cursor should end up on the last inserted character. + * Don't do it for CTRL-O, unless past the end of the line. + */ + if (!nomove + && (curwin->w_cursor.col != 0 + || curwin->w_cursor.coladd > 0) + && (restart_edit == NUL + || (gchar_cursor() == NUL && !VIsual_active)) +#ifdef FEAT_RIGHTLEFT + && !revins_on +#endif + ) + { + if (curwin->w_cursor.coladd > 0 || get_ve_flags() == VE_ALL) + { + oneleft(); + if (restart_edit != NUL) + ++curwin->w_cursor.coladd; + } + else + { + --curwin->w_cursor.col; + // Correct cursor for multi-byte character. + if (has_mbyte) + mb_adjust_cursor(); + } + } + +#ifdef HAVE_INPUT_METHOD + // Disable IM to allow typing English directly for Normal mode commands. + // When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as + // well). + if (!(State & MODE_LANGMAP)) + im_save_status(&curbuf->b_p_iminsert); + im_set_active(FALSE); +#endif + + State = MODE_NORMAL; + may_trigger_modechanged(); + // need to position cursor again when on a TAB + if (gchar_cursor() == TAB) + curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); + + setmouse(); +#ifdef CURSOR_SHAPE + ui_cursor_shape(); // may show different cursor shape +#endif + if (!p_ek) + { + MAY_WANT_TO_LOG_THIS; + + // Re-enable bracketed paste mode. + out_str_t_BE(); + + // Re-enable modifyOtherKeys. + out_str_t_TI(); + } +#ifdef FEAT_CONCEAL + // Check if the cursor line needs redrawing after changing State. If + // 'concealcursor' is "i" it needs to be redrawn without concealing. + conceal_check_cursor_line(cursor_line_was_concealed); +#endif + + // When recording or for CTRL-O, need to display the new mode. + // Otherwise remove the mode message. + if (reg_recording != 0 || restart_edit != NUL) + showmode(); + else if (p_smd && (got_int || !skip_showmode())) + msg(""); + + return TRUE; // exit Insert mode +} + +#ifdef FEAT_RIGHTLEFT +/* + * Toggle language: hkmap and revins_on. + * Move to end of reverse inserted text. + */ + static void +ins_ctrl_(void) +{ + if (revins_on && revins_chars && revins_scol >= 0) + { + while (gchar_cursor() != NUL && revins_chars--) + ++curwin->w_cursor.col; + } + p_ri = !p_ri; + revins_on = (State == MODE_INSERT && p_ri); + if (revins_on) + { + revins_scol = curwin->w_cursor.col; + revins_legal++; + revins_chars = 0; + undisplay_dollar(); + } + else + revins_scol = -1; + p_hkmap = curwin->w_p_rl ^ p_ri; // be consistent! + showmode(); +} +#endif + +/* + * If 'keymodel' contains "startsel", may start selection. + * Returns TRUE when a CTRL-O and other keys stuffed. + */ + static int +ins_start_select(int c) +{ + if (!km_startsel) + return FALSE; + switch (c) + { + case K_KHOME: + case K_KEND: + case K_PAGEUP: + case K_KPAGEUP: + case K_PAGEDOWN: + case K_KPAGEDOWN: +# ifdef MACOS_X + case K_LEFT: + case K_RIGHT: + case K_UP: + case K_DOWN: + case K_END: + case K_HOME: +# endif + if (!(mod_mask & MOD_MASK_SHIFT)) + break; + // FALLTHROUGH + case K_S_LEFT: + case K_S_RIGHT: + case K_S_UP: + case K_S_DOWN: + case K_S_END: + case K_S_HOME: + // Start selection right away, the cursor can move with CTRL-O when + // beyond the end of the line. + start_selection(); + + // Execute the key in (insert) Select mode. + stuffcharReadbuff(Ctrl_O); + if (mod_mask) + { + char_u buf[4]; + + buf[0] = K_SPECIAL; + buf[1] = KS_MODIFIER; + buf[2] = mod_mask; + buf[3] = NUL; + stuffReadbuff(buf); + } + stuffcharReadbuff(c); + return TRUE; + } + return FALSE; +} + +/* + * key in Insert mode: toggle insert/replace mode. + */ + static void +ins_insert(int replaceState) +{ +#ifdef FEAT_EVAL + set_vim_var_string(VV_INSERTMODE, + (char_u *)((State & REPLACE_FLAG) ? "i" + : replaceState == MODE_VREPLACE ? "v" : "r"), 1); +#endif + ins_apply_autocmds(EVENT_INSERTCHANGE); + if (State & REPLACE_FLAG) + State = MODE_INSERT | (State & MODE_LANGMAP); + else + State = replaceState | (State & MODE_LANGMAP); + may_trigger_modechanged(); + AppendCharToRedobuff(K_INS); + showmode(); +#ifdef CURSOR_SHAPE + ui_cursor_shape(); // may show different cursor shape +#endif +} + +/* + * Pressed CTRL-O in Insert mode. + */ + static void +ins_ctrl_o(void) +{ + if (State & VREPLACE_FLAG) + restart_edit = 'V'; + else if (State & REPLACE_FLAG) + restart_edit = 'R'; + else + restart_edit = 'I'; + if (virtual_active()) + ins_at_eol = FALSE; // cursor always keeps its column + else + ins_at_eol = (gchar_cursor() == NUL); +} + +/* + * If the cursor is on an indent, ^T/^D insert/delete one + * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>". + * Always round the indent to 'shiftwidth', this is compatible + * with vi. But vi only supports ^T and ^D after an + * autoindent, we support it everywhere. + */ + static void +ins_shift(int c, int lastc) +{ + if (stop_arrow() == FAIL) + return; + AppendCharToRedobuff(c); + + /* + * 0^D and ^^D: remove all indent. + */ + if (c == Ctrl_D && (lastc == '0' || lastc == '^') + && curwin->w_cursor.col > 0) + { + --curwin->w_cursor.col; + (void)del_char(FALSE); // delete the '^' or '0' + // In Replace mode, restore the characters that '^' or '0' replaced. + if (State & REPLACE_FLAG) + replace_pop_ins(); + if (lastc == '^') + old_indent = get_indent(); // remember curr. indent + change_indent(INDENT_SET, 0, TRUE, 0, TRUE); + } + else + change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0, TRUE); + + if (did_ai && *skipwhite(ml_get_curline()) != NUL) + did_ai = FALSE; + did_si = FALSE; + can_si = FALSE; + can_si_back = FALSE; + can_cindent = FALSE; // no cindenting after ^D or ^T +} + + static void +ins_del(void) +{ + int temp; + + if (stop_arrow() == FAIL) + return; + if (gchar_cursor() == NUL) // delete newline + { + temp = curwin->w_cursor.col; + if (!can_bs(BS_EOL) // only if "eol" included + || do_join(2, FALSE, TRUE, FALSE, FALSE) == FAIL) + vim_beep(BO_BS); + else + { + curwin->w_cursor.col = temp; + // Adjust orig_line_count in case more lines have been deleted than + // have been added. That makes sure, that open_line() later + // can access all buffer lines correctly + if (State & VREPLACE_FLAG && + orig_line_count > curbuf->b_ml.ml_line_count) + orig_line_count = curbuf->b_ml.ml_line_count; + } + } + else if (del_char(FALSE) == FAIL) // delete char under cursor + vim_beep(BO_BS); + did_ai = FALSE; + did_si = FALSE; + can_si = FALSE; + can_si_back = FALSE; + AppendCharToRedobuff(K_DEL); +} + +/* + * Delete one character for ins_bs(). + */ + static void +ins_bs_one(colnr_T *vcolp) +{ + dec_cursor(); + getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL); + if (State & REPLACE_FLAG) + { + // Don't delete characters before the insert point when in + // Replace mode + if (curwin->w_cursor.lnum != Insstart.lnum + || curwin->w_cursor.col >= Insstart.col) + replace_do_bs(-1); + } + else + (void)del_char(FALSE); +} + +/* + * Handle Backspace, delete-word and delete-line in Insert mode. + * Return TRUE when backspace was actually used. + */ + static int +ins_bs( + int c, + int mode, + int *inserted_space_p) +{ + linenr_T lnum; + int cc; + int temp = 0; // init for GCC + colnr_T save_col; + colnr_T mincol; + int did_backspace = FALSE; + int in_indent; + int oldState; + int cpc[MAX_MCO]; // composing characters + int call_fix_indent = FALSE; + + /* + * can't delete anything in an empty file + * can't backup past first character in buffer + * can't backup past starting point unless 'backspace' > 1 + * can backup to a previous line if 'backspace' == 0 + */ + if ( BUFEMPTY() + || ( +#ifdef FEAT_RIGHTLEFT + !revins_on && +#endif + ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0) + || (!can_bs(BS_START) + && ((arrow_used +#ifdef FEAT_JOB_CHANNEL + && !bt_prompt(curbuf) +#endif + ) || (curwin->w_cursor.lnum == Insstart_orig.lnum + && curwin->w_cursor.col <= Insstart_orig.col))) + || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0 + && curwin->w_cursor.col <= ai_col) + || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0)))) + { + vim_beep(BO_BS); + return FALSE; + } + + if (stop_arrow() == FAIL) + return FALSE; + in_indent = inindent(0); + if (in_indent) + can_cindent = FALSE; + end_comment_pending = NUL; // After BS, don't auto-end comment +#ifdef FEAT_RIGHTLEFT + if (revins_on) // put cursor after last inserted char + inc_cursor(); +#endif + + // Virtualedit: + // BACKSPACE_CHAR eats a virtual space + // BACKSPACE_WORD eats all coladd + // BACKSPACE_LINE eats all coladd and keeps going + if (curwin->w_cursor.coladd > 0) + { + if (mode == BACKSPACE_CHAR) + { + --curwin->w_cursor.coladd; + return TRUE; + } + if (mode == BACKSPACE_WORD) + { + curwin->w_cursor.coladd = 0; + return TRUE; + } + curwin->w_cursor.coladd = 0; + } + + /* + * Delete newline! + */ + if (curwin->w_cursor.col == 0) + { + lnum = Insstart.lnum; + if (curwin->w_cursor.lnum == lnum +#ifdef FEAT_RIGHTLEFT + || revins_on +#endif + ) + { + if (u_save((linenr_T)(curwin->w_cursor.lnum - 2), + (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL) + return FALSE; + --Insstart.lnum; + Insstart.col = (colnr_T)STRLEN(ml_get(Insstart.lnum)); + } + /* + * In replace mode: + * cc < 0: NL was inserted, delete it + * cc >= 0: NL was replaced, put original characters back + */ + cc = -1; + if (State & REPLACE_FLAG) + cc = replace_pop(); // returns -1 if NL was inserted + /* + * In replace mode, in the line we started replacing, we only move the + * cursor. + */ + if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum) + { + dec_cursor(); + } + else + { + if (!(State & VREPLACE_FLAG) + || curwin->w_cursor.lnum > orig_line_count) + { + temp = gchar_cursor(); // remember current char + --curwin->w_cursor.lnum; + + // When "aw" is in 'formatoptions' we must delete the space at + // the end of the line, otherwise the line will be broken + // again when auto-formatting. + if (has_format_option(FO_AUTO) + && has_format_option(FO_WHITE_PAR)) + { + char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, + TRUE); + int len; + + len = (int)STRLEN(ptr); + if (len > 0 && ptr[len - 1] == ' ') + ptr[len - 1] = NUL; + } + + (void)do_join(2, FALSE, FALSE, FALSE, FALSE); + if (temp == NUL && gchar_cursor() != NUL) + inc_cursor(); + } + else + dec_cursor(); + + /* + * In MODE_REPLACE mode we have to put back the text that was + * replaced by the NL. On the replace stack is first a + * NUL-terminated sequence of characters that were deleted and then + * the characters that NL replaced. + */ + if (State & REPLACE_FLAG) + { + /* + * Do the next ins_char() in MODE_NORMAL state, to + * prevent ins_char() from replacing characters and + * avoiding showmatch(). + */ + oldState = State; + State = MODE_NORMAL; + /* + * restore characters (blanks) deleted after cursor + */ + while (cc > 0) + { + save_col = curwin->w_cursor.col; + mb_replace_pop_ins(cc); + curwin->w_cursor.col = save_col; + cc = replace_pop(); + } + // restore the characters that NL replaced + replace_pop_ins(); + State = oldState; + } + } + did_ai = FALSE; + } + else + { + /* + * Delete character(s) before the cursor. + */ +#ifdef FEAT_RIGHTLEFT + if (revins_on) // put cursor on last inserted char + dec_cursor(); +#endif + mincol = 0; + // keep indent + if (mode == BACKSPACE_LINE + && (curbuf->b_p_ai || cindent_on()) +#ifdef FEAT_RIGHTLEFT + && !revins_on +#endif + ) + { + save_col = curwin->w_cursor.col; + beginline(BL_WHITE); + if (curwin->w_cursor.col < save_col) + { + mincol = curwin->w_cursor.col; + // should now fix the indent to match with the previous line + call_fix_indent = TRUE; + } + curwin->w_cursor.col = save_col; + } + + /* + * Handle deleting one 'shiftwidth' or 'softtabstop'. + */ + if ( mode == BACKSPACE_CHAR + && ((p_sta && in_indent) + || ((get_sts_value() != 0 +#ifdef FEAT_VARTABS + || tabstop_count(curbuf->b_p_vsts_array) +#endif + ) + && curwin->w_cursor.col > 0 + && (*(ml_get_cursor() - 1) == TAB + || (*(ml_get_cursor() - 1) == ' ' + && (!*inserted_space_p + || arrow_used)))))) + { + int ts; + colnr_T vcol; + colnr_T want_vcol; + colnr_T start_vcol; + + *inserted_space_p = FALSE; + // Compute the virtual column where we want to be. Since + // 'showbreak' may get in the way, need to get the last column of + // the previous character. + getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); + start_vcol = vcol; + dec_cursor(); + getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol); + inc_cursor(); +#ifdef FEAT_VARTABS + if (p_sta && in_indent) + { + ts = (int)get_sw_value(curbuf); + want_vcol = (want_vcol / ts) * ts; + } + else + want_vcol = tabstop_start(want_vcol, get_sts_value(), + curbuf->b_p_vsts_array); +#else + if (p_sta && in_indent) + ts = (int)get_sw_value(curbuf); + else + ts = (int)get_sts_value(); + want_vcol = (want_vcol / ts) * ts; +#endif + + // delete characters until we are at or before want_vcol + while (vcol > want_vcol && curwin->w_cursor.col > 0 + && (cc = *(ml_get_cursor() - 1), VIM_ISWHITE(cc))) + ins_bs_one(&vcol); + + // insert extra spaces until we are at want_vcol + while (vcol < want_vcol) + { + // Remember the first char we inserted + if (curwin->w_cursor.lnum == Insstart_orig.lnum + && curwin->w_cursor.col < Insstart_orig.col) + Insstart_orig.col = curwin->w_cursor.col; + + if (State & VREPLACE_FLAG) + ins_char(' '); + else + { + ins_str((char_u *)" "); + if ((State & REPLACE_FLAG)) + replace_push(NUL); + } + getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); + } + + // If we are now back where we started delete one character. Can + // happen when using 'sts' and 'linebreak'. + if (vcol >= start_vcol) + ins_bs_one(&vcol); + } + + /* + * Delete up to starting point, start of line or previous word. + */ + else + { + int cclass = 0, prev_cclass = 0; + + if (has_mbyte) + cclass = mb_get_class(ml_get_cursor()); + do + { +#ifdef FEAT_RIGHTLEFT + if (!revins_on) // put cursor on char to be deleted +#endif + dec_cursor(); + + cc = gchar_cursor(); + // look multi-byte character class + if (has_mbyte) + { + prev_cclass = cclass; + cclass = mb_get_class(ml_get_cursor()); + } + + // start of word? + if (mode == BACKSPACE_WORD && !vim_isspace(cc)) + { + mode = BACKSPACE_WORD_NOT_SPACE; + temp = vim_iswordc(cc); + } + // end of word? + else if (mode == BACKSPACE_WORD_NOT_SPACE + && ((vim_isspace(cc) || vim_iswordc(cc) != temp) + || prev_cclass != cclass)) + { +#ifdef FEAT_RIGHTLEFT + if (!revins_on) +#endif + inc_cursor(); +#ifdef FEAT_RIGHTLEFT + else if (State & REPLACE_FLAG) + dec_cursor(); +#endif + break; + } + if (State & REPLACE_FLAG) + replace_do_bs(-1); + else + { + if (enc_utf8 && p_deco) + (void)utfc_ptr2char(ml_get_cursor(), cpc); + (void)del_char(FALSE); + /* + * If there are combining characters and 'delcombine' is set + * move the cursor back. Don't back up before the base + * character. + */ + if (enc_utf8 && p_deco && cpc[0] != NUL) + inc_cursor(); +#ifdef FEAT_RIGHTLEFT + if (revins_chars) + { + revins_chars--; + revins_legal++; + } + if (revins_on && gchar_cursor() == NUL) + break; +#endif + } + // Just a single backspace?: + if (mode == BACKSPACE_CHAR) + break; + } while ( +#ifdef FEAT_RIGHTLEFT + revins_on || +#endif + (curwin->w_cursor.col > mincol + && (can_bs(BS_NOSTOP) + || (curwin->w_cursor.lnum != Insstart_orig.lnum + || curwin->w_cursor.col != Insstart_orig.col) + ))); + } + did_backspace = TRUE; + } + did_si = FALSE; + can_si = FALSE; + can_si_back = FALSE; + if (curwin->w_cursor.col <= 1) + did_ai = FALSE; + + if (call_fix_indent) + fix_indent(); + + /* + * It's a little strange to put backspaces into the redo + * buffer, but it makes auto-indent a lot easier to deal + * with. + */ + AppendCharToRedobuff(c); + + // If deleted before the insertion point, adjust it + if (curwin->w_cursor.lnum == Insstart_orig.lnum + && curwin->w_cursor.col < Insstart_orig.col) + Insstart_orig.col = curwin->w_cursor.col; + + // vi behaviour: the cursor moves backward but the character that + // was there remains visible + // Vim behaviour: the cursor moves backward and the character that + // was there is erased from the screen. + // We can emulate the vi behaviour by pretending there is a dollar + // displayed even when there isn't. + // --pkv Sun Jan 19 01:56:40 EST 2003 + if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == -1) + dollar_vcol = curwin->w_virtcol; + +#ifdef FEAT_FOLDING + // When deleting a char the cursor line must never be in a closed fold. + // E.g., when 'foldmethod' is indent and deleting the first non-white + // char before a Tab. + if (did_backspace) + foldOpenCursor(); +#endif + + return did_backspace; +} + +/* + * Handle receiving P_PS: start paste mode. Inserts the following text up to + * P_PE literally. + * When "drop" is TRUE then consume the text and drop it. + */ + int +bracketed_paste(paste_mode_T mode, int drop, garray_T *gap) +{ + int c; + char_u buf[NUMBUFLEN + MB_MAXBYTES]; + int idx = 0; + char_u *end = find_termcode((char_u *)"PE"); + int ret_char = -1; + int save_allow_keys = allow_keys; + int save_paste = p_paste; + + // If the end code is too long we can't detect it, read everything. + if (end != NULL && STRLEN(end) >= NUMBUFLEN) + end = NULL; + ++no_mapping; + allow_keys = 0; + if (!p_paste) + // Also have the side effects of setting 'paste' to make it work much + // faster. + set_option_value_give_err((char_u *)"paste", TRUE, NULL, 0); + + for (;;) + { + // When the end is not defined read everything there is. + if (end == NULL && vpeekc() == NUL) + break; + do + c = vgetc(); + while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR); + + if (c == NUL || got_int || (ex_normal_busy > 0 && c == Ctrl_C)) + // When CTRL-C was encountered the typeahead will be flushed and we + // won't get the end sequence. Except when using ":normal". + break; + + if (has_mbyte) + idx += (*mb_char2bytes)(c, buf + idx); + else + buf[idx++] = c; + buf[idx] = NUL; + if (end != NULL && STRNCMP(buf, end, idx) == 0) + { + if (end[idx] == NUL) + break; // Found the end of paste code. + continue; + } + if (!drop) + { + switch (mode) + { + case PASTE_CMDLINE: + put_on_cmdline(buf, idx, TRUE); + break; + + case PASTE_EX: + // add one for the NUL that is going to be appended + if (gap != NULL && ga_grow(gap, idx + 1) == OK) + { + mch_memmove((char *)gap->ga_data + gap->ga_len, + buf, (size_t)idx); + gap->ga_len += idx; + } + break; + + case PASTE_INSERT: + if (stop_arrow() == OK) + { + c = buf[0]; + if (idx == 1 && (c == CAR || c == K_KENTER || c == NL)) + ins_eol(c); + else + { + ins_char_bytes(buf, idx); + AppendToRedobuffLit(buf, idx); + } + } + break; + + case PASTE_ONE_CHAR: + if (ret_char == -1) + { + if (has_mbyte) + ret_char = (*mb_ptr2char)(buf); + else + ret_char = buf[0]; + } + break; + } + } + idx = 0; + } + + --no_mapping; + allow_keys = save_allow_keys; + if (!save_paste) + set_option_value_give_err((char_u *)"paste", FALSE, NULL, 0); + + return ret_char; +} + +#if defined(FEAT_GUI_TABLINE) || defined(PROTO) + static void +ins_tabline(int c) +{ + // We will be leaving the current window, unless closing another tab. + if (c != K_TABMENU || current_tabmenu != TABLINE_MENU_CLOSE + || (current_tab != 0 && current_tab != tabpage_index(curtab))) + { + undisplay_dollar(); + start_arrow(&curwin->w_cursor); + can_cindent = TRUE; + } + + if (c == K_TABLINE) + goto_tabpage(current_tab); + else + { + handle_tabmenu(); + redraw_statuslines(); // will redraw the tabline when needed + } +} +#endif + +#if defined(FEAT_GUI) || defined(PROTO) + void +ins_scroll(void) +{ + pos_T tpos; + + undisplay_dollar(); + tpos = curwin->w_cursor; + if (gui_do_scroll()) + { + start_arrow(&tpos); + can_cindent = TRUE; + } +} + + void +ins_horscroll(void) +{ + pos_T tpos; + + undisplay_dollar(); + tpos = curwin->w_cursor; + if (do_mousescroll_horiz(scrollbar_value)) + { + start_arrow(&tpos); + can_cindent = TRUE; + } +} +#endif + + static void +ins_left(void) +{ + pos_T tpos; + int end_change = dont_sync_undo == FALSE; // end undoable change + +#ifdef FEAT_FOLDING + if ((fdo_flags & FDO_HOR) && KeyTyped) + foldOpenCursor(); +#endif + undisplay_dollar(); + tpos = curwin->w_cursor; + if (oneleft() == OK) + { +#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) + // Only call start_arrow() when not busy with preediting, it will + // break undo. K_LEFT is inserted in im_correct_cursor(). + if (p_imst == IM_OVER_THE_SPOT || !im_is_preediting()) +#endif + { + start_arrow_with_change(&tpos, end_change); + if (!end_change) + AppendCharToRedobuff(K_LEFT); + } +#ifdef FEAT_RIGHTLEFT + // If exit reversed string, position is fixed + if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol) + revins_legal++; + revins_chars++; +#endif + } + + /* + * if 'whichwrap' set for cursor in insert mode may go to + * previous line + */ + else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1) + { + // always break undo when moving upwards/downwards, else undo may break + start_arrow(&tpos); + --(curwin->w_cursor.lnum); + coladvance((colnr_T)MAXCOL); + curwin->w_set_curswant = TRUE; // so we stay at the end + } + else + vim_beep(BO_CRSR); + dont_sync_undo = FALSE; +} + + static void +ins_home(int c) +{ + pos_T tpos; + +#ifdef FEAT_FOLDING + if ((fdo_flags & FDO_HOR) && KeyTyped) + foldOpenCursor(); +#endif + undisplay_dollar(); + tpos = curwin->w_cursor; + if (c == K_C_HOME) + curwin->w_cursor.lnum = 1; + curwin->w_cursor.col = 0; + curwin->w_cursor.coladd = 0; + curwin->w_curswant = 0; + start_arrow(&tpos); +} + + static void +ins_end(int c) +{ + pos_T tpos; + +#ifdef FEAT_FOLDING + if ((fdo_flags & FDO_HOR) && KeyTyped) + foldOpenCursor(); +#endif + undisplay_dollar(); + tpos = curwin->w_cursor; + if (c == K_C_END) + curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; + coladvance((colnr_T)MAXCOL); + curwin->w_curswant = MAXCOL; + + start_arrow(&tpos); +} + + static void +ins_s_left(void) +{ + int end_change = dont_sync_undo == FALSE; // end undoable change +#ifdef FEAT_FOLDING + if ((fdo_flags & FDO_HOR) && KeyTyped) + foldOpenCursor(); +#endif + undisplay_dollar(); + if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0) + { + start_arrow_with_change(&curwin->w_cursor, end_change); + if (!end_change) + AppendCharToRedobuff(K_S_LEFT); + (void)bck_word(1L, FALSE, FALSE); + curwin->w_set_curswant = TRUE; + } + else + vim_beep(BO_CRSR); + dont_sync_undo = FALSE; +} + + static void +ins_right(void) +{ + int end_change = dont_sync_undo == FALSE; // end undoable change + +#ifdef FEAT_FOLDING + if ((fdo_flags & FDO_HOR) && KeyTyped) + foldOpenCursor(); +#endif + undisplay_dollar(); + if (gchar_cursor() != NUL || virtual_active()) + { + start_arrow_with_change(&curwin->w_cursor, end_change); + if (!end_change) + AppendCharToRedobuff(K_RIGHT); + curwin->w_set_curswant = TRUE; + if (virtual_active()) + oneright(); + else + { + if (has_mbyte) + curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor()); + else + ++curwin->w_cursor.col; + } + +#ifdef FEAT_RIGHTLEFT + revins_legal++; + if (revins_chars) + revins_chars--; +#endif + } + // if 'whichwrap' set for cursor in insert mode, may move the + // cursor to the next line + else if (vim_strchr(p_ww, ']') != NULL + && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) + { + start_arrow(&curwin->w_cursor); + curwin->w_set_curswant = TRUE; + ++curwin->w_cursor.lnum; + curwin->w_cursor.col = 0; + } + else + vim_beep(BO_CRSR); + dont_sync_undo = FALSE; +} + + static void +ins_s_right(void) +{ + int end_change = dont_sync_undo == FALSE; // end undoable change +#ifdef FEAT_FOLDING + if ((fdo_flags & FDO_HOR) && KeyTyped) + foldOpenCursor(); +#endif + undisplay_dollar(); + if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count + || gchar_cursor() != NUL) + { + start_arrow_with_change(&curwin->w_cursor, end_change); + if (!end_change) + AppendCharToRedobuff(K_S_RIGHT); + (void)fwd_word(1L, FALSE, 0); + curwin->w_set_curswant = TRUE; + } + else + vim_beep(BO_CRSR); + dont_sync_undo = FALSE; +} + + static void +ins_up( + int startcol) // when TRUE move to Insstart.col +{ + pos_T tpos; + linenr_T old_topline = curwin->w_topline; +#ifdef FEAT_DIFF + int old_topfill = curwin->w_topfill; +#endif + + undisplay_dollar(); + tpos = curwin->w_cursor; + if (cursor_up(1L, TRUE) == OK) + { + if (startcol) + coladvance(getvcol_nolist(&Insstart)); + if (old_topline != curwin->w_topline +#ifdef FEAT_DIFF + || old_topfill != curwin->w_topfill +#endif + ) + redraw_later(UPD_VALID); + start_arrow(&tpos); + can_cindent = TRUE; + } + else + vim_beep(BO_CRSR); +} + + static void +ins_pageup(void) +{ + pos_T tpos; + + undisplay_dollar(); + + if (mod_mask & MOD_MASK_CTRL) + { + // : tab page back + if (first_tabpage->tp_next != NULL) + { + start_arrow(&curwin->w_cursor); + goto_tabpage(-1); + } + return; + } + + tpos = curwin->w_cursor; + if (onepage(BACKWARD, 1L) == OK) + { + start_arrow(&tpos); + can_cindent = TRUE; + } + else + vim_beep(BO_CRSR); +} + + static void +ins_down( + int startcol) // when TRUE move to Insstart.col +{ + pos_T tpos; + linenr_T old_topline = curwin->w_topline; +#ifdef FEAT_DIFF + int old_topfill = curwin->w_topfill; +#endif + + undisplay_dollar(); + tpos = curwin->w_cursor; + if (cursor_down(1L, TRUE) == OK) + { + if (startcol) + coladvance(getvcol_nolist(&Insstart)); + if (old_topline != curwin->w_topline +#ifdef FEAT_DIFF + || old_topfill != curwin->w_topfill +#endif + ) + redraw_later(UPD_VALID); + start_arrow(&tpos); + can_cindent = TRUE; + } + else + vim_beep(BO_CRSR); +} + + static void +ins_pagedown(void) +{ + pos_T tpos; + + undisplay_dollar(); + + if (mod_mask & MOD_MASK_CTRL) + { + // : tab page forward + if (first_tabpage->tp_next != NULL) + { + start_arrow(&curwin->w_cursor); + goto_tabpage(0); + } + return; + } + + tpos = curwin->w_cursor; + if (onepage(FORWARD, 1L) == OK) + { + start_arrow(&tpos); + can_cindent = TRUE; + } + else + vim_beep(BO_CRSR); +} + +#ifdef FEAT_DND + static void +ins_drop(void) +{ + do_put('~', NULL, BACKWARD, 1L, PUT_CURSEND); +} +#endif + +/* + * Handle TAB in Insert or Replace mode. + * Return TRUE when the TAB needs to be inserted like a normal character. + */ + static int +ins_tab(void) +{ + int ind; + int i; + int temp; + + if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum) + Insstart_blank_vcol = get_nolist_virtcol(); + if (echeck_abbr(TAB + ABBR_OFF)) + return FALSE; + + ind = inindent(0); + if (ind) + can_cindent = FALSE; + + /* + * When nothing special, insert TAB like a normal character. + */ + if (!curbuf->b_p_et +#ifdef FEAT_VARTABS + && !(p_sta && ind + // These five lines mean 'tabstop' != 'shiftwidth' + && ((tabstop_count(curbuf->b_p_vts_array) > 1) + || (tabstop_count(curbuf->b_p_vts_array) == 1 + && tabstop_first(curbuf->b_p_vts_array) + != get_sw_value(curbuf)) + || (tabstop_count(curbuf->b_p_vts_array) == 0 + && curbuf->b_p_ts != get_sw_value(curbuf)))) + && tabstop_count(curbuf->b_p_vsts_array) == 0 +#else + && !(p_sta && ind && curbuf->b_p_ts != get_sw_value(curbuf)) +#endif + && get_sts_value() == 0) + return TRUE; + + if (stop_arrow() == FAIL) + return TRUE; + + did_ai = FALSE; + did_si = FALSE; + can_si = FALSE; + can_si_back = FALSE; + AppendToRedobuff((char_u *)"\t"); + +#ifdef FEAT_VARTABS + if (p_sta && ind) // insert tab in indent, use 'shiftwidth' + { + temp = (int)get_sw_value(curbuf); + temp -= get_nolist_virtcol() % temp; + } + else if (tabstop_count(curbuf->b_p_vsts_array) > 0 || curbuf->b_p_sts != 0) + // use 'softtabstop' when set + temp = tabstop_padding(get_nolist_virtcol(), get_sts_value(), + curbuf->b_p_vsts_array); + else // otherwise use 'tabstop' + temp = tabstop_padding(get_nolist_virtcol(), curbuf->b_p_ts, + curbuf->b_p_vts_array); +#else + if (p_sta && ind) // insert tab in indent, use 'shiftwidth' + temp = (int)get_sw_value(curbuf); + else if (curbuf->b_p_sts != 0) // use 'softtabstop' when set + temp = (int)get_sts_value(); + else // otherwise use 'tabstop' + temp = (int)curbuf->b_p_ts; + temp -= get_nolist_virtcol() % temp; +#endif + + /* + * Insert the first space with ins_char(). It will delete one char in + * replace mode. Insert the rest with ins_str(); it will not delete any + * chars. For MODE_VREPLACE state, we use ins_char() for all characters. + */ + ins_char(' '); + while (--temp > 0) + { + if (State & VREPLACE_FLAG) + ins_char(' '); + else + { + ins_str((char_u *)" "); + if (State & REPLACE_FLAG) // no char replaced + replace_push(NUL); + } + } + + /* + * When 'expandtab' not set: Replace spaces by TABs where possible. + */ +#ifdef FEAT_VARTABS + if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0 + || get_sts_value() > 0 + || (p_sta && ind))) +#else + if (!curbuf->b_p_et && (get_sts_value() || (p_sta && ind))) +#endif + { + char_u *ptr; + char_u *saved_line = NULL; // init for GCC + pos_T pos; + pos_T fpos; + pos_T *cursor; + colnr_T want_vcol, vcol; + int change_col = -1; + int save_list = curwin->w_p_list; + char_u *tab = (char_u *)"\t"; + chartabsize_T cts; + + /* + * Get the current line. For MODE_VREPLACE state, don't make real + * changes yet, just work on a copy of the line. + */ + if (State & VREPLACE_FLAG) + { + pos = curwin->w_cursor; + cursor = &pos; + saved_line = vim_strsave(ml_get_curline()); + if (saved_line == NULL) + return FALSE; + ptr = saved_line + pos.col; + } + else + { + ptr = ml_get_cursor(); + cursor = &curwin->w_cursor; + } + + // When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. + if (vim_strchr(p_cpo, CPO_LISTWM) == NULL) + curwin->w_p_list = FALSE; + + // Find first white before the cursor + fpos = curwin->w_cursor; + while (fpos.col > 0 && VIM_ISWHITE(ptr[-1])) + { + --fpos.col; + --ptr; + } + + // In Replace mode, don't change characters before the insert point. + if ((State & REPLACE_FLAG) + && fpos.lnum == Insstart.lnum + && fpos.col < Insstart.col) + { + ptr += Insstart.col - fpos.col; + fpos.col = Insstart.col; + } + + // compute virtual column numbers of first white and cursor + getvcol(curwin, &fpos, &vcol, NULL, NULL); + getvcol(curwin, cursor, &want_vcol, NULL, NULL); + + init_chartabsize_arg(&cts, curwin, 0, vcol, tab, tab); + + // Use as many TABs as possible. Beware of 'breakindent', 'showbreak' + // and 'linebreak' adding extra virtual columns. + while (VIM_ISWHITE(*ptr)) + { + i = lbr_chartabsize(&cts); + if (cts.cts_vcol + i > want_vcol) + break; + if (*ptr != TAB) + { + *ptr = TAB; + if (change_col < 0) + { + change_col = fpos.col; // Column of first change + // May have to adjust Insstart + if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col) + Insstart.col = fpos.col; + } + } + ++fpos.col; + ++ptr; + cts.cts_vcol += i; + } + vcol = cts.cts_vcol; + clear_chartabsize_arg(&cts); + + if (change_col >= 0) + { + int repl_off = 0; + + // Skip over the spaces we need. + init_chartabsize_arg(&cts, curwin, 0, vcol, ptr, ptr); + while (cts.cts_vcol < want_vcol && *cts.cts_ptr == ' ') + { + cts.cts_vcol += lbr_chartabsize(&cts); + ++cts.cts_ptr; + ++repl_off; + } + ptr = cts.cts_ptr; + vcol = cts.cts_vcol; + clear_chartabsize_arg(&cts); + + if (vcol > want_vcol) + { + // Must have a char with 'showbreak' just before it. + --ptr; + --repl_off; + } + fpos.col += repl_off; + + // Delete following spaces. + i = cursor->col - fpos.col; + if (i > 0) + { +#ifdef FEAT_PROP_POPUP + if (!(State & VREPLACE_FLAG)) + { + char_u *newp; + int col; + + newp = alloc(curbuf->b_ml.ml_line_len - i); + if (newp == NULL) + return FALSE; + + col = ptr - curbuf->b_ml.ml_line_ptr; + if (col > 0) + mch_memmove(newp, ptr - col, col); + mch_memmove(newp + col, ptr + i, + curbuf->b_ml.ml_line_len - col - i); + + if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) + vim_free(curbuf->b_ml.ml_line_ptr); + curbuf->b_ml.ml_line_ptr = newp; + curbuf->b_ml.ml_line_len -= i; + curbuf->b_ml.ml_flags = + (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; + } + else +#endif + STRMOVE(ptr, ptr + i); + // correct replace stack. + if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) + for (temp = i; --temp >= 0; ) + replace_join(repl_off); + } +#ifdef FEAT_NETBEANS_INTG + if (netbeans_active()) + { + netbeans_removed(curbuf, fpos.lnum, cursor->col, (long)(i + 1)); + netbeans_inserted(curbuf, fpos.lnum, cursor->col, + (char_u *)"\t", 1); + } +#endif + cursor->col -= i; + + /* + * In MODE_VREPLACE state, we haven't changed anything yet. Do it + * now by backspacing over the changed spacing and then inserting + * the new spacing. + */ + if (State & VREPLACE_FLAG) + { + // Backspace from real cursor to change_col + backspace_until_column(change_col); + + // Insert each char in saved_line from changed_col to + // ptr-cursor + ins_bytes_len(saved_line + change_col, + cursor->col - change_col); + } + } + + if (State & VREPLACE_FLAG) + vim_free(saved_line); + curwin->w_p_list = save_list; + } + + return FALSE; +} + +/* + * Handle CR or NL in insert mode. + * Return FAIL when out of memory or can't undo. + */ + int +ins_eol(int c) +{ + int i; + + if (echeck_abbr(c + ABBR_OFF)) + return OK; + if (stop_arrow() == FAIL) + return FAIL; + undisplay_dollar(); + + /* + * Strange Vi behaviour: In Replace mode, typing a NL will not delete the + * character under the cursor. Only push a NUL on the replace stack, + * nothing to put back when the NL is deleted. + */ + if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) + replace_push(NUL); + + /* + * In MODE_VREPLACE state, a NL replaces the rest of the line, and starts + * replacing the next line, so we push all of the characters left on the + * line onto the replace stack. This is not done here though, it is done + * in open_line(). + */ + + // Put cursor on NUL if on the last char and coladd is 1 (happens after + // CTRL-O). + if (virtual_active() && curwin->w_cursor.coladd > 0) + coladvance(getviscol()); + +#ifdef FEAT_RIGHTLEFT + // NL in reverse insert will always start in the end of + // current line. + if (revins_on) + curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor()); +#endif + + AppendToRedobuff(NL_STR); + i = open_line(FORWARD, + has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM : 0, old_indent, + NULL); + old_indent = 0; + can_cindent = TRUE; +#ifdef FEAT_FOLDING + // When inserting a line the cursor line must never be in a closed fold. + foldOpenCursor(); +#endif + + return i; +} + +#ifdef FEAT_DIGRAPHS +/* + * Handle digraph in insert mode. + * Returns character still to be inserted, or NUL when nothing remaining to be + * done. + */ + static int +ins_digraph(void) +{ + int c; + int cc; + int did_putchar = FALSE; + + pc_status = PC_STATUS_UNSET; + if (redrawing() && !char_avail()) + { + // may need to redraw when no more chars available now + ins_redraw(FALSE); + + edit_putchar('?', TRUE); + did_putchar = TRUE; + add_to_showcmd_c(Ctrl_K); + } + +#ifdef USE_ON_FLY_SCROLL + dont_scroll = TRUE; // disallow scrolling here +#endif + + // don't map the digraph chars. This also prevents the + // mode message to be deleted when ESC is hit + ++no_mapping; + ++allow_keys; + c = plain_vgetc(); + --no_mapping; + --allow_keys; + if (did_putchar) + // when the line fits in 'columns' the '?' is at the start of the next + // line and will not be removed by the redraw + edit_unputchar(); + + if (IS_SPECIAL(c) || mod_mask) // special key + { + clear_showcmd(); + insert_special(c, TRUE, FALSE); + return NUL; + } + if (c != ESC) + { + did_putchar = FALSE; + if (redrawing() && !char_avail()) + { + // may need to redraw when no more chars available now + ins_redraw(FALSE); + + if (char2cells(c) == 1) + { + ins_redraw(FALSE); + edit_putchar(c, TRUE); + did_putchar = TRUE; + } + add_to_showcmd_c(c); + } + ++no_mapping; + ++allow_keys; + cc = plain_vgetc(); + --no_mapping; + --allow_keys; + if (did_putchar) + // when the line fits in 'columns' the '?' is at the start of the + // next line and will not be removed by a redraw + edit_unputchar(); + if (cc != ESC) + { + AppendToRedobuff((char_u *)CTRL_V_STR); + c = digraph_get(c, cc, TRUE); + clear_showcmd(); + return c; + } + } + clear_showcmd(); + return NUL; +} +#endif + +/* + * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line. + * Returns the char to be inserted, or NUL if none found. + */ + int +ins_copychar(linenr_T lnum) +{ + int c; + char_u *ptr, *prev_ptr; + char_u *line; + chartabsize_T cts; + + if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) + { + vim_beep(BO_COPY); + return NUL; + } + + // try to advance to the cursor column + validate_virtcol(); + line = ml_get(lnum); + prev_ptr = line; + init_chartabsize_arg(&cts, curwin, lnum, 0, line, line); + while (cts.cts_vcol < curwin->w_virtcol && *cts.cts_ptr != NUL) + { + prev_ptr = cts.cts_ptr; + cts.cts_vcol += lbr_chartabsize_adv(&cts); + } + if (cts.cts_vcol > curwin->w_virtcol) + ptr = prev_ptr; + else + ptr = cts.cts_ptr; + clear_chartabsize_arg(&cts); + + c = (*mb_ptr2char)(ptr); + if (c == NUL) + vim_beep(BO_COPY); + return c; +} + +/* + * CTRL-Y or CTRL-E typed in Insert mode. + */ + static int +ins_ctrl_ey(int tc) +{ + int c = tc; + + if (ctrl_x_mode_scroll()) + { + if (c == Ctrl_Y) + scrolldown_clamp(); + else + scrollup_clamp(); + redraw_later(UPD_VALID); + } + else + { + c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1)); + if (c != NUL) + { + long tw_save; + + // The character must be taken literally, insert like it + // was typed after a CTRL-V, and pretend 'textwidth' + // wasn't set. Digits, 'o' and 'x' are special after a + // CTRL-V, don't use it for these. + if (c < 256 && !isalnum(c)) + AppendToRedobuff((char_u *)CTRL_V_STR); // CTRL-V + tw_save = curbuf->b_p_tw; + curbuf->b_p_tw = -1; + insert_special(c, TRUE, FALSE); + curbuf->b_p_tw = tw_save; +#ifdef FEAT_RIGHTLEFT + revins_chars++; + revins_legal++; +#endif + c = Ctrl_V; // pretend CTRL-V is last character + auto_format(FALSE, TRUE); + } + } + return c; +} + +/* + * Get the value that w_virtcol would have when 'list' is off. + * Unless 'cpo' contains the 'L' flag. + */ + colnr_T +get_nolist_virtcol(void) +{ + // check validity of cursor in current buffer + if (curwin->w_buffer == NULL + || curwin->w_buffer->b_ml.ml_mfp == NULL + || curwin->w_cursor.lnum > curwin->w_buffer->b_ml.ml_line_count) + return 0; + if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) + return getvcol_nolist(&curwin->w_cursor); + validate_virtcol(); + return curwin->w_virtcol; +} + +#if defined(FEAT_EVAL) +/* + * Handle the InsertCharPre autocommand. + * "c" is the character that was typed. + * Return a pointer to allocated memory with the replacement string. + * Return NULL to continue inserting "c". + */ + static char_u * +do_insert_char_pre(int c) +{ + char_u *res; + char_u buf[MB_MAXBYTES + 1]; + int save_State = State; + + // Return quickly when there is nothing to do. + if (!has_insertcharpre()) + return NULL; + + if (has_mbyte) + buf[(*mb_char2bytes)(c, buf)] = NUL; + else + { + buf[0] = c; + buf[1] = NUL; + } + + // Lock the text to avoid weird things from happening. + ++textlock; + set_vim_var_string(VV_CHAR, buf, -1); // set v:char + + res = NULL; + if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) + { + // Get the value of v:char. It may be empty or more than one + // character. Only use it when changed, otherwise continue with the + // original character to avoid breaking autoindent. + if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) + res = vim_strsave(get_vim_var_str(VV_CHAR)); + } + + set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char + --textlock; + + // Restore the State, it may have been changed. + State = save_State; + + return res; +} +#endif + + int +get_can_cindent(void) +{ + return can_cindent; +} + + void +set_can_cindent(int val) +{ + can_cindent = val; +} + +/* + * Trigger "event" and take care of fixing undo. + */ + int +ins_apply_autocmds(event_T event) +{ + varnumber_T tick = CHANGEDTICK(curbuf); + int r; + + r = apply_autocmds(event, NULL, NULL, FALSE, curbuf); + + // If u_savesub() was called then we are not prepared to start + // a new line. Call u_save() with no contents to fix that. + // Except when leaving Insert mode. + if (event != EVENT_INSERTLEAVE && tick != CHANGEDTICK(curbuf)) + u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1)); + + return r; +} diff --git a/src/errors.h b/src/errors.h new file mode 100644 index 0000000..445a9b8 --- /dev/null +++ b/src/errors.h @@ -0,0 +1,3457 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * Definition of error messages, sorted on error number. + */ + +EXTERN char e_interrupted[] + INIT(= N_("Interrupted")); + +EXTERN char e_backslash_should_be_followed_by[] + INIT(= N_("E10: \\ should be followed by /, ? or &")); +EXTERN char e_invalid_in_cmdline_window[] + INIT(= N_("E11: Invalid in command-line window; :q closes the window")); +EXTERN char e_command_not_allowed_from_vimrc_in_current_dir_or_tag_search[] + INIT(= N_("E12: Command not allowed from exrc/vimrc in current dir or tag search")); +EXTERN char e_file_exists[] + INIT(= N_("E13: File exists (add ! to override)")); +// E14 unused +#ifdef FEAT_EVAL +EXTERN char e_invalid_expression_str[] + INIT(= N_("E15: Invalid expression: \"%s\"")); +#endif +EXTERN char e_invalid_range[] + INIT(= N_("E16: Invalid range")); +#if defined(UNIX) || defined(FEAT_SYN_HL) \ + || defined(FEAT_SPELL) || defined(FEAT_EVAL) +EXTERN char e_str_is_directory[] + INIT(= N_("E17: \"%s\" is a directory")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_unexpected_characters_in_let[] + INIT(= N_("E18: Unexpected characters in :let")); +EXTERN char e_unexpected_characters_in_assignment[] + INIT(= N_("E18: Unexpected characters in assignment")); +#endif +EXTERN char e_mark_has_invalid_line_number[] + INIT(= N_("E19: Mark has invalid line number")); +EXTERN char e_mark_not_set[] + INIT(= N_("E20: Mark not set")); +EXTERN char e_cannot_make_changes_modifiable_is_off[] + INIT(= N_("E21: Cannot make changes, 'modifiable' is off")); +EXTERN char e_scripts_nested_too_deep[] + INIT(= N_("E22: Scripts nested too deep")); +EXTERN char e_no_alternate_file[] + INIT(= N_("E23: No alternate file")); +EXTERN char e_no_such_abbreviation[] + INIT(= N_("E24: No such abbreviation")); +#if !defined(FEAT_GUI) || defined(VIMDLL) +EXTERN char e_gui_cannot_be_used_not_enabled_at_compile_time[] + INIT(= N_("E25: GUI cannot be used: Not enabled at compile time")); +#endif +#ifndef FEAT_RIGHTLEFT +EXTERN char e_hebrew_cannot_be_used_not_enabled_at_compile_time[] + INIT(= N_("E26: Hebrew cannot be used: Not enabled at compile time\n")); +#endif +EXTERN char e_farsi_support_has_been_removed[] + INIT(= N_("E27: Farsi support has been removed\n")); +#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_SYN_HL) +EXTERN char e_no_such_highlight_group_name_str[] + INIT(= N_("E28: No such highlight group name: %s")); +#endif +EXTERN char e_no_inserted_text_yet[] + INIT(= N_("E29: No inserted text yet")); +EXTERN char e_no_previous_command_line[] + INIT(= N_("E30: No previous command line")); +EXTERN char e_no_such_mapping[] + INIT(= N_("E31: No such mapping")); +EXTERN char e_no_file_name[] + INIT(= N_("E32: No file name")); +EXTERN char e_no_previous_substitute_regular_expression[] + INIT(= N_("E33: No previous substitute regular expression")); +EXTERN char e_no_previous_command[] + INIT(= N_("E34: No previous command")); +EXTERN char e_no_previous_regular_expression[] + INIT(= N_("E35: No previous regular expression")); +EXTERN char e_not_enough_room[] + INIT(= N_("E36: Not enough room")); +EXTERN char e_no_write_since_last_change[] + INIT(= N_("E37: No write since last change")); +EXTERN char e_no_write_since_last_change_add_bang_to_override[] + INIT(= N_("E37: No write since last change (add ! to override)")); +EXTERN char e_null_argument[] + INIT(= N_("E38: Null argument")); +#if defined(FEAT_DIGRAPHS) || defined(FEAT_TIMERS) || defined(FEAT_EVAL) +EXTERN char e_number_expected[] + INIT(= N_("E39: Number expected")); +#endif +#ifdef FEAT_QUICKFIX +EXTERN char e_cant_open_errorfile_str[] + INIT(= N_("E40: Can't open errorfile %s")); +#endif +EXTERN char e_out_of_memory[] + INIT(= N_("E41: Out of memory!")); +#ifdef FEAT_QUICKFIX +EXTERN char e_no_errors[] + INIT(= N_("E42: No Errors")); +#endif +EXTERN char e_damaged_match_string[] + INIT(= N_("E43: Damaged match string")); +EXTERN char e_corrupted_regexp_program[] + INIT(= N_("E44: Corrupted regexp program")); +EXTERN char e_readonly_option_is_set_add_bang_to_override[] + INIT(= N_("E45: 'readonly' option is set (add ! to override)")); +#ifdef FEAT_EVAL +EXTERN char e_cannot_change_readonly_variable[] + INIT(= N_("E46: Cannot change read-only variable")); +EXTERN char e_cannot_change_readonly_variable_str[] + INIT(= N_("E46: Cannot change read-only variable \"%s\"")); +#endif +#ifdef FEAT_QUICKFIX +EXTERN char e_error_while_reading_errorfile[] + INIT(= N_("E47: Error while reading errorfile")); +#endif +#ifdef HAVE_SANDBOX +EXTERN char e_not_allowed_in_sandbox[] + INIT(= N_("E48: Not allowed in sandbox")); +#endif +EXTERN char e_invalid_scroll_size[] + INIT(= N_("E49: Invalid scroll size")); +#ifdef FEAT_SYN_HL +EXTERN char e_too_many_z[] + INIT(= N_("E50: Too many \\z(")); +#endif +EXTERN char e_too_many_str_open[] + INIT(= N_("E51: Too many %s(")); +#ifdef FEAT_SYN_HL +EXTERN char e_unmatched_z[] + INIT(= N_("E52: Unmatched \\z(")); +#endif +EXTERN char e_unmatched_str_percent_open[] + INIT(= N_("E53: Unmatched %s%%(")); +EXTERN char e_unmatched_str_open[] + INIT(= N_("E54: Unmatched %s(")); +EXTERN char e_unmatched_str_close[] + INIT(= N_("E55: Unmatched %s)")); +// E56 unused +// E57 unused +// E58 unused +EXTERN char e_invalid_character_after_str_at[] + INIT(= N_("E59: Invalid character after %s@")); +EXTERN char e_too_many_complex_str_curly[] + INIT(= N_("E60: Too many complex %s{...}s")); +EXTERN char e_nested_str[] + INIT(= N_("E61: Nested %s*")); +EXTERN char e_nested_str_chr[] + INIT(= N_("E62: Nested %s%c")); +EXTERN char e_invalid_use_of_underscore[] + INIT(= N_("E63: Invalid use of \\_")); +EXTERN char e_str_chr_follows_nothing[] + INIT(= N_("E64: %s%c follows nothing")); +EXTERN char e_illegal_back_reference[] + INIT(= N_("E65: Illegal back reference")); +#ifdef FEAT_SYN_HL +EXTERN char e_z_not_allowed_here[] + INIT(= N_("E66: \\z( not allowed here")); +EXTERN char e_z1_z9_not_allowed_here[] + INIT(= N_("E67: \\z1 - \\z9 not allowed here")); +#endif +EXTERN char e_invalid_character_after_bsl_z[] + INIT(= N_("E68: Invalid character after \\z")); +EXTERN char e_missing_sb_after_str[] + INIT(= N_("E69: Missing ] after %s%%[")); +EXTERN char e_empty_str_brackets[] + INIT(= N_("E70: Empty %s%%[]")); +EXTERN char e_invalid_character_after_str[] + INIT(= N_("E71: Invalid character after %s%%")); +EXTERN char e_close_error_on_swap_file[] + INIT(= N_("E72: Close error on swap file")); +EXTERN char e_tag_stack_empty[] + INIT(= N_("E73: Tag stack empty")); +EXTERN char e_command_too_complex[] + INIT(= N_("E74: Command too complex")); +EXTERN char e_name_too_long[] + INIT(= N_("E75: Name too long")); +EXTERN char e_too_many_brackets[] + INIT(= N_("E76: Too many [")); +EXTERN char e_too_many_file_names[] + INIT(= N_("E77: Too many file names")); +EXTERN char e_unknown_mark[] + INIT(= N_("E78: Unknown mark")); +EXTERN char e_cannot_expand_wildcards[] + INIT(= N_("E79: Cannot expand wildcards")); +EXTERN char e_error_while_writing[] + INIT(= N_("E80: Error while writing")); +#ifdef FEAT_EVAL +EXTERN char e_using_sid_not_in_script_context[] + INIT(= N_("E81: Using not in a script context")); +#endif +EXTERN char e_cannot_allocate_any_buffer_exiting[] + INIT(= N_("E82: Cannot allocate any buffer, exiting...")); +EXTERN char e_cannot_allocate_buffer_using_other_one[] + INIT(= N_("E83: Cannot allocate buffer, using other one...")); +EXTERN char e_no_modified_buffer_found[] + INIT(= N_("E84: No modified buffer found")); +EXTERN char e_there_is_no_listed_buffer[] + INIT(= N_("E85: There is no listed buffer")); +EXTERN char e_buffer_nr_does_not_exist[] + INIT(= N_("E86: Buffer %ld does not exist")); +EXTERN char e_cannot_go_beyond_last_buffer[] + INIT(= N_("E87: Cannot go beyond last buffer")); +EXTERN char e_cannot_go_before_first_buffer[] + INIT(= N_("E88: Cannot go before first buffer")); +EXTERN char e_no_write_since_last_change_for_buffer_nr_add_bang_to_override[] + INIT(= N_("E89: No write since last change for buffer %d (add ! to override)")); +EXTERN char e_cannot_unload_last_buffer[] + INIT(= N_("E90: Cannot unload last buffer")); +EXTERN char e_shell_option_is_empty[] + INIT(= N_("E91: 'shell' option is empty")); +EXTERN char e_buffer_nr_not_found[] + INIT(= N_("E92: Buffer %d not found")); +EXTERN char e_more_than_one_match_for_str[] + INIT(= N_("E93: More than one match for %s")); +EXTERN char e_no_matching_buffer_for_str[] + INIT(= N_("E94: No matching buffer for %s")); +EXTERN char e_buffer_with_this_name_already_exists[] + INIT(= N_("E95: Buffer with this name already exists")); +#if defined(FEAT_DIFF) +EXTERN char e_cannot_diff_more_than_nr_buffers[] + INIT(= N_("E96: Cannot diff more than %d buffers")); +EXTERN char e_cannot_create_diffs[] + INIT(= N_("E97: Cannot create diffs")); +EXTERN char e_cannot_read_diff_output[] + INIT(= N_("E98: Cannot read diff output")); +EXTERN char e_current_buffer_is_not_in_diff_mode[] + INIT(= N_("E99: Current buffer is not in diff mode")); +EXTERN char e_no_other_buffer_in_diff_mode[] + INIT(= N_("E100: No other buffer in diff mode")); +EXTERN char e_more_than_two_buffers_in_diff_mode_dont_know_which_one_to_use[] + INIT(= N_("E101: More than two buffers in diff mode, don't know which one to use")); +EXTERN char e_cant_find_buffer_str[] + INIT(= N_("E102: Can't find buffer \"%s\"")); +EXTERN char e_buffer_str_is_not_in_diff_mode[] + INIT(= N_("E103: Buffer \"%s\" is not in diff mode")); +#endif +#ifdef FEAT_DIGRAPHS +EXTERN char e_escape_not_allowed_in_digraph[] + INIT(= N_("E104: Escape not allowed in digraph")); +#endif +#ifdef FEAT_KEYMAP +EXTERN char e_using_loadkeymap_not_in_sourced_file[] + INIT(= N_("E105: Using :loadkeymap not in a sourced file")); +#endif +// E106 unused +#ifdef FEAT_EVAL +EXTERN char e_missing_parenthesis_str[] + INIT(= N_("E107: Missing parentheses: %s")); +EXTERN char e_no_such_variable_str[] + INIT(= N_("E108: No such variable: \"%s\"")); +EXTERN char e_missing_colon_after_questionmark[] + INIT(= N_("E109: Missing ':' after '?'")); +EXTERN char e_missing_closing_paren[] + INIT(= N_("E110: Missing ')'")); +EXTERN char e_missing_closing_square_brace[] + INIT(= N_("E111: Missing ']'")); +EXTERN char e_option_name_missing_str[] + INIT(= N_("E112: Option name missing: %s")); +EXTERN char e_unknown_option_str[] + INIT(= N_("E113: Unknown option: %s")); +EXTERN char e_missing_double_quote_str[] + INIT(= N_("E114: Missing double quote: %s")); +EXTERN char e_missing_single_quote_str[] + INIT(= N_("E115: Missing single quote: %s")); +EXTERN char e_invalid_arguments_for_function_str[] + INIT(= N_("E116: Invalid arguments for function %s")); +EXTERN char e_unknown_function_str[] + INIT(= N_("E117: Unknown function: %s")); +EXTERN char e_too_many_arguments_for_function_str[] + INIT(= N_("E118: Too many arguments for function: %s")); +EXTERN char e_not_enough_arguments_for_function_str[] + INIT(= N_("E119: Not enough arguments for function: %s")); +EXTERN char e_using_sid_not_in_script_context_str[] + INIT(= N_("E120: Using not in a script context: %s")); +EXTERN char e_undefined_variable_str[] + INIT(= N_("E121: Undefined variable: %s")); +EXTERN char e_undefined_variable_char_str[] + INIT(= N_("E121: Undefined variable: %c:%s")); +EXTERN char e_function_str_already_exists_add_bang_to_replace[] + INIT(= N_("E122: Function %s already exists, add ! to replace it")); +EXTERN char e_undefined_function_str[] + INIT(= N_("E123: Undefined function: %s")); +EXTERN char e_missing_paren_str[] + INIT(= N_("E124: Missing '(': %s")); +EXTERN char e_illegal_argument_str[] + INIT(= N_("E125: Illegal argument: %s")); +EXTERN char e_missing_endfunction[] + INIT(= N_("E126: Missing :endfunction")); +EXTERN char e_cannot_redefine_function_str_it_is_in_use[] + INIT(= N_("E127: Cannot redefine function %s: It is in use")); +EXTERN char e_function_name_must_start_with_capital_or_s_str[] + INIT(= N_("E128: Function name must start with a capital or \"s:\": %s")); +EXTERN char e_function_name_required[] + INIT(= N_("E129: Function name required")); +// E130 unused +EXTERN char e_cannot_delete_function_str_it_is_in_use[] + INIT(= N_("E131: Cannot delete function %s: It is in use")); +EXTERN char e_function_call_depth_is_higher_than_macfuncdepth[] + INIT(= N_("E132: Function call depth is higher than 'maxfuncdepth'")); +EXTERN char e_return_not_inside_function[] + INIT(= N_("E133: :return not inside a function")); +#endif +EXTERN char e_cannot_move_range_of_lines_into_itself[] + INIT(= N_("E134: Cannot move a range of lines into itself")); +EXTERN char e_filter_autocommands_must_not_change_current_buffer[] + INIT(= N_("E135: *Filter* Autocommands must not change current buffer")); +#if defined(FEAT_VIMINFO) +EXTERN char e_viminfo_too_many_errors_skipping_rest_of_file[] + INIT(= N_("E136: viminfo: Too many errors, skipping rest of file")); +EXTERN char e_viminfo_file_is_not_writable_str[] + INIT(= N_("E137: Viminfo file is not writable: %s")); +EXTERN char e_cant_write_viminfo_file_str[] + INIT(= N_("E138: Can't write viminfo file %s!")); +#endif +EXTERN char e_file_is_loaded_in_another_buffer[] + INIT(= N_("E139: File is loaded in another buffer")); +EXTERN char e_use_bang_to_write_partial_buffer[] + INIT(= N_("E140: Use ! to write partial buffer")); +EXTERN char e_no_file_name_for_buffer_nr[] + INIT(= N_("E141: No file name for buffer %ld")); +EXTERN char e_file_not_written_writing_is_disabled_by_write_option[] + INIT(= N_("E142: File not written: Writing is disabled by 'write' option")); +EXTERN char e_autocommands_unexpectedly_deleted_new_buffer_str[] + INIT(= N_("E143: Autocommands unexpectedly deleted new buffer %s")); +EXTERN char e_non_numeric_argument_to_z[] + INIT(= N_("E144: Non-numeric argument to :z")); +EXTERN char e_shell_commands_and_some_functionality_not_allowed_in_rvim[] + INIT(= N_("E145: Shell commands and some functionality not allowed in rvim")); +EXTERN char e_regular_expressions_cant_be_delimited_by_letters[] + INIT(= N_("E146: Regular expressions can't be delimited by letters")); +EXTERN char e_cannot_do_global_recursive_with_range[] + INIT(= N_("E147: Cannot do :global recursive with a range")); +EXTERN char e_regular_expression_missing_from_global[] + INIT(= N_("E148: Regular expression missing from :global")); +EXTERN char e_sorry_no_help_for_str[] + INIT(= N_("E149: Sorry, no help for %s")); +EXTERN char e_not_a_directory_str[] + INIT(= N_("E150: Not a directory: %s")); +EXTERN char e_no_match_str_1[] + INIT(= N_("E151: No match: %s")); +EXTERN char e_cannot_open_str_for_writing_1[] + INIT(= N_("E152: Cannot open %s for writing")); +EXTERN char e_unable_to_open_str_for_reading[] + INIT(= N_("E153: Unable to open %s for reading")); +EXTERN char e_duplicate_tag_str_in_file_str_str[] + INIT(= N_("E154: Duplicate tag \"%s\" in file %s/%s")); +#ifdef FEAT_SIGNS +EXTERN char e_unknown_sign_str[] + INIT(= N_("E155: Unknown sign: %s")); +EXTERN char e_missing_sign_name[] + INIT(= N_("E156: Missing sign name")); +EXTERN char e_invalid_sign_id_nr[] + INIT(= N_("E157: Invalid sign ID: %d")); +#endif +#if defined(FEAT_SIGNS) || defined(FEAT_EVAL) +EXTERN char e_invalid_buffer_name_str[] + INIT(= N_("E158: Invalid buffer name: %s")); +#endif +#ifdef FEAT_SIGNS +EXTERN char e_missing_sign_number[] + INIT(= N_("E159: Missing sign number")); +EXTERN char e_unknown_sign_command_str[] + INIT(= N_("E160: Unknown sign command: %s")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_breakpoint_not_found_str[] + INIT(= N_("E161: Breakpoint not found: %s")); +#endif +EXTERN char e_no_write_since_last_change_for_buffer_str[] + INIT(= N_("E162: No write since last change for buffer \"%s\"")); +EXTERN char e_there_is_only_one_file_to_edit[] + INIT(= N_("E163: There is only one file to edit")); +EXTERN char e_cannot_go_before_first_file[] + INIT(= N_("E164: Cannot go before first file")); +EXTERN char e_cannot_go_beyond_last_file[] + INIT(= N_("E165: Cannot go beyond last file")); +EXTERN char e_cant_open_linked_file_for_writing[] + INIT(= N_("E166: Can't open linked file for writing")); +EXTERN char e_scriptencoding_used_outside_of_sourced_file[] + INIT(= N_("E167: :scriptencoding used outside of a sourced file")); +#ifdef FEAT_EVAL +EXTERN char e_finish_used_outside_of_sourced_file[] + INIT(= N_("E168: :finish used outside of a sourced file")); +#endif +EXTERN char e_command_too_recursive[] + INIT(= N_("E169: Command too recursive")); +#ifdef FEAT_EVAL +EXTERN char e_missing_endwhile[] + INIT(= N_("E170: Missing :endwhile")); +EXTERN char e_missing_endfor[] + INIT(= N_("E170: Missing :endfor")); +EXTERN char e_missing_endif[] + INIT(= N_("E171: Missing :endif")); +EXTERN char e_missing_marker[] + INIT(= N_("E172: Missing marker")); +#endif +EXTERN char e_nr_more_file_to_edit[] + INIT(= N_("E173: %d more file to edit")); +EXTERN char e_nr_more_files_to_edit[] + INIT(= N_("E173: %d more files to edit")); +EXTERN char e_command_already_exists_add_bang_to_replace_it_str[] + INIT(= N_("E174: Command already exists: add ! to replace it: %s")); +EXTERN char e_no_attribute_specified[] + INIT(= N_("E175: No attribute specified")); +EXTERN char e_invalid_number_of_arguments[] + INIT(= N_("E176: Invalid number of arguments")); +EXTERN char e_count_cannot_be_specified_twice[] + INIT(= N_("E177: Count cannot be specified twice")); +EXTERN char e_invalid_default_value_for_count[] + INIT(= N_("E178: Invalid default value for count")); +EXTERN char e_argument_required_for_str[] + INIT(= N_("E179: Argument required for %s")); +EXTERN char e_invalid_complete_value_str[] + INIT(= N_("E180: Invalid complete value: %s")); +EXTERN char e_invalid_address_type_value_str[] + INIT(= N_("E180: Invalid address type value: %s")); +EXTERN char e_invalid_attribute_str[] + INIT(= N_("E181: Invalid attribute: %s")); +EXTERN char e_invalid_command_name[] + INIT(= N_("E182: Invalid command name")); +EXTERN char e_user_defined_commands_must_start_with_an_uppercase_letter[] + INIT(= N_("E183: User defined commands must start with an uppercase letter")); +EXTERN char e_no_such_user_defined_command_str[] + INIT(= N_("E184: No such user-defined command: %s")); +EXTERN char e_cannot_find_color_scheme_str[] + INIT(= N_("E185: Cannot find color scheme '%s'")); +EXTERN char e_no_previous_directory[] + INIT(= N_("E186: No previous directory")); +EXTERN char e_directory_unknown[] + INIT(= N_("E187: Directory unknown")); +EXTERN char e_obtaining_window_position_not_implemented_for_this_platform[] + INIT(= N_("E188: Obtaining window position not implemented for this platform")); +EXTERN char e_str_exists_add_bang_to_override[] + INIT(= N_("E189: \"%s\" exists (add ! to override)")); +EXTERN char e_cannot_open_str_for_writing_2[] + INIT(= N_("E190: Cannot open \"%s\" for writing")); +EXTERN char e_argument_must_be_letter_or_forward_backward_quote[] + INIT(= N_("E191: Argument must be a letter or forward/backward quote")); +EXTERN char e_recursive_use_of_normal_too_deep[] + INIT(= N_("E192: Recursive use of :normal too deep")); +#ifdef FEAT_EVAL +EXTERN char e_str_not_inside_function[] + INIT(= N_("E193: %s not inside a function")); +#endif +EXTERN char e_no_alternate_file_name_to_substitute_for_hash[] + INIT(= N_("E194: No alternate file name to substitute for '#'")); +#ifdef FEAT_VIMINFO +EXTERN char e_cannot_open_viminfo_file_for_reading[] + INIT(= N_("E195: Cannot open viminfo file for reading")); +#endif +#ifndef FEAT_DIGRAPHS +EXTERN char e_no_digraphs_version[] + INIT(= N_("E196: No digraphs in this version")); +#endif +EXTERN char e_cannot_set_language_to_str[] + INIT(= N_("E197: Cannot set language to \"%s\"")); +// E198 unused +EXTERN char e_active_window_or_buffer_deleted[] + INIT(= N_("E199: Active window or buffer deleted")); +EXTERN char e_readpre_autocommands_made_file_unreadable[] + INIT(= N_("E200: *ReadPre autocommands made the file unreadable")); +EXTERN char e_readpre_autocommands_must_not_change_current_buffer[] + INIT(= N_("E201: *ReadPre autocommands must not change current buffer")); +#ifdef FEAT_EVAL +EXTERN char e_conversion_mad_file_unreadable[] + INIT(= N_("E202: Conversion made file unreadable!")); +#endif +EXTERN char e_autocommands_deleted_or_unloaded_buffer_to_be_written[] + INIT(= N_("E203: Autocommands deleted or unloaded buffer to be written")); +EXTERN char e_autocommands_changed_number_of_lines_in_unexpected_way[] + INIT(= N_("E204: Autocommand changed number of lines in unexpected way")); +EXTERN char e_patchmode_cant_save_original_file[] + INIT(= N_("E205: Patchmode: can't save original file")); +EXTERN char e_patchmode_cant_touch_empty_original_file[] + INIT(= N_("E206: Patchmode: can't touch empty original file")); +EXTERN char e_cant_delete_backup_file[] + INIT(= N_("E207: Can't delete backup file")); +EXTERN char e_error_writing_to_str[] + INIT(= N_("E208: Error writing to \"%s\"")); +EXTERN char e_error_closing_str[] + INIT(= N_("E209: Error closing \"%s\"")); +EXTERN char e_error_reading_str[] + INIT(= N_("E210: Error reading \"%s\"")); +EXTERN char e_file_str_no_longer_available[] + INIT(= N_("E211: File \"%s\" no longer available")); +EXTERN char e_cant_open_file_for_writing[] + INIT(= N_("E212: Can't open file for writing")); +EXTERN char e_cannot_convert_add_bang_to_write_without_conversion[] + INIT(= N_("E213: Cannot convert (add ! to write without conversion)")); +#ifdef FEAT_EVAL +EXTERN char e_cant_find_temp_file_for_writing[] + INIT(= N_("E214: Can't find temp file for writing")); +#endif +EXTERN char e_illegal_character_after_star_str[] + INIT(= N_("E215: Illegal character after *: %s")); +EXTERN char e_no_such_event_str[] + INIT(= N_("E216: No such event: %s")); +EXTERN char e_no_such_group_or_event_str[] + INIT(= N_("E216: No such group or event: %s")); +EXTERN char e_cant_execute_autocommands_for_all_events[] + INIT(= N_("E217: Can't execute autocommands for ALL events")); +EXTERN char e_autocommand_nesting_too_deep[] + INIT(= N_("E218: Autocommand nesting too deep")); +EXTERN char e_missing_open_curly[] + INIT(= N_("E219: Missing {.")); +EXTERN char e_missing_close_curly[] + INIT(= N_("E220: Missing }.")); +#ifdef FEAT_EVAL +EXTERN char e_marker_cannot_start_with_lower_case_letter[] + INIT(= N_("E221: Marker cannot start with lower case letter")); +#endif +EXTERN char e_add_to_internal_buffer_that_was_already_read_from[] + INIT(= N_("E222: Add to internal buffer that was already read from")); +EXTERN char e_recursive_mapping[] + INIT(= N_("E223: Recursive mapping")); +EXTERN char e_global_abbreviation_already_exists_for_str[] + INIT(= N_("E224: Global abbreviation already exists for %s")); +EXTERN char e_global_mapping_already_exists_for_str[] + INIT(= N_("E225: Global mapping already exists for %s")); +EXTERN char e_abbreviation_already_exists_for_str[] + INIT(= N_("E226: Abbreviation already exists for %s")); +EXTERN char e_mapping_already_exists_for_str[] + INIT(= N_("E227: Mapping already exists for %s")); +EXTERN char e_makemap_illegal_mode[] + INIT(= N_("E228: makemap: Illegal mode")); +#ifdef FEAT_GUI +EXTERN char e_cannot_start_the_GUI[] + INIT(= N_("E229: Cannot start the GUI")); +EXTERN char e_cannot_read_from_str[] + INIT(= N_("E230: Cannot read from \"%s\"")); +EXTERN char e_guifontwide_invalid[] + INIT(= N_("E231: 'guifontwide' invalid")); +#ifdef FEAT_BEVAL_GUI +EXTERN char e_cannot_create_ballooneval_with_both_message_and_callback[] + INIT(= N_("E232: Cannot create BalloonEval with both message and callback")); +#endif +# if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) +EXTERN char e_cannot_open_display[] + INIT(= N_("E233: Cannot open display")); +# endif +# if defined(FEAT_XFONTSET) +EXTERN char e_unknown_fontset_str[] + INIT(= N_("E234: Unknown fontset: %s")); +# endif +# if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) \ + || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_HAIKU) +EXTERN char e_unknown_font_str[] + INIT(= N_("E235: Unknown font: %s")); +# endif +# if defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK) +EXTERN char e_font_str_is_not_fixed_width[] + INIT(= N_("E236: Font \"%s\" is not fixed-width")); +# endif +#endif +#ifdef MSWIN +EXTERN char e_printer_selection_failed[] + INIT(= N_("E237: Printer selection failed")); +EXTERN char e_print_error_str[] + INIT(= N_("E238: Print error: %s")); +#endif +#ifdef FEAT_SIGNS +EXTERN char e_invalid_sign_text_str[] + INIT(= N_("E239: Invalid sign text: %s")); +#endif +#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) +EXTERN char e_no_connection_to_x_server[] + INIT(= N_("E240: No connection to the X server")); +#endif +#ifdef FEAT_CLIENTSERVER +EXTERN char e_unable_to_send_to_str[] + INIT(= N_("E241: Unable to send to %s")); +#endif +EXTERN char e_cant_split_window_while_closing_another[] + INIT(= N_("E242: Can't split a window while closing another")); +#if defined(FEAT_GUI_MSWIN) && !defined(FEAT_OLE) +EXTERN char e_argument_not_supported_str_use_ole_version[] + INIT(= N_("E243: Argument not supported: \"-%s\"; Use the OLE version.")); +#endif +#ifdef MSWIN +EXTERN char e_illegal_str_name_str_in_font_name_str[] + INIT(= N_("E244: Illegal %s name \"%s\" in font name \"%s\"")); +EXTERN char e_illegal_char_nr_in_font_name_str[] + INIT(= N_("E245: Illegal char '%c' in font name \"%s\"")); +#endif +EXTERN char e_filechangedshell_autocommand_deleted_buffer[] + INIT(= N_("E246: FileChangedShell autocommand deleted buffer")); +#ifdef FEAT_CLIENTSERVER +EXTERN char e_no_registered_server_named_str[] + INIT(= N_("E247: No registered server named \"%s\"")); +EXTERN char e_failed_to_send_command_to_destination_program[] + INIT(= N_("E248: Failed to send command to the destination program")); +#endif +EXTERN char e_window_layout_changed_unexpectedly[] + INIT(= N_("E249: Window layout changed unexpectedly")); +#ifdef FEAT_XFONTSET +EXTERN char e_fonts_for_the_following_charsets_are_missing_in_fontset[] + INIT(= N_("E250: Fonts for the following charsets are missing in fontset %s:")); +#endif +#ifdef FEAT_CLIENTSERVER +EXTERN char e_vim_instance_registry_property_is_badly_formed_deleted[] + INIT(= N_("E251: VIM instance registry property is badly formed. Deleted!")); +#endif +#ifdef FEAT_GUI_X11 +EXTERN char e_fontsent_name_str_font_str_is_not_fixed_width[] + INIT(= N_("E252: Fontset name: %s - Font '%s' is not fixed-width")); +EXTERN char e_fontset_name_str[] + INIT(= N_("E253: Fontset name: %s")); +#endif +#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) +EXTERN char e_cannot_allocate_color_str[] + INIT(= N_("E254: Cannot allocate color %s")); +#endif +#if defined(FEAT_SIGN_ICONS) && !defined(FEAT_GUI_GTK) +EXTERN char e_couldnt_read_in_sign_data[] + INIT(= N_("E255: Couldn't read in sign data")); +#endif +// E256 unused +#ifdef FEAT_CSCOPE +EXTERN char e_cstag_tag_not_founc[] + INIT(= N_("E257: cstag: Tag not found")); +#endif +#ifdef FEAT_CLIENTSERVER +EXTERN char e_unable_to_send_to_client[] + INIT(= N_("E258: Unable to send to client")); +#endif +#ifdef FEAT_CSCOPE +EXTERN char e_no_matches_found_for_cscope_query_str_of_str[] + INIT(= N_("E259: No matches found for cscope query %s of %s")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_missing_name_after_method[] + INIT(= N_("E260: Missing name after ->")); +#endif +#ifdef FEAT_CSCOPE +EXTERN char e_cscope_connection_str_not_founc[] + INIT(= N_("E261: Cscope connection %s not found")); +EXTERN char e_error_reading_cscope_connection_nr[] + INIT(= N_("E262: Error reading cscope connection %d")); +#endif +#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3) +EXTERN char e_sorry_this_command_is_disabled_python_library_could_not_be_found[] + INIT(= N_("E263: Sorry, this command is disabled, the Python library could not be loaded.")); +#endif +#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) +EXTERN char e_python_error_initialising_io_object[] + INIT(= N_("E264: Python: Error initialising I/O objects")); +#endif +#ifdef FEAT_RUBY +EXTERN char e_dollar_must_be_an_instance_of_string[] + INIT(= N_("E265: $_ must be an instance of String")); +#endif +#ifdef DYNAMIC_RUBY +EXTERN char e_sorry_this_command_is_disabled_the_ruby_library_could_not_be_loaded[] + INIT(= N_("E266: Sorry, this command is disabled, the Ruby library could not be loaded.")); +#endif +#ifdef FEAT_RUBY +EXTERN char e_unexpected_return[] + INIT(= N_("E267: Unexpected return")); +EXTERN char e_unexpected_next[] + INIT(= N_("E268: Unexpected next")); +EXTERN char e_unexpected_break[] + INIT(= N_("E269: Unexpected break")); +EXTERN char e_unexpected_redo[] + INIT(= N_("E270: Unexpected redo")); +EXTERN char e_retry_outside_of_rescue_clause[] + INIT(= N_("E271: Retry outside of rescue clause")); +EXTERN char e_unhandled_exception[] + INIT(= N_("E272: Unhandled exception")); +EXTERN char e_unknown_longjmp_status_nr[] + INIT(= N_("E273: Unknown longjmp status %d")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_no_white_space_allowed_before_parenthesis[] + INIT(= N_("E274: No white space allowed before parenthesis")); +#endif +#ifdef FEAT_PROP_POPUP +EXTERN char e_cannot_add_text_property_to_unloaded_buffer[] + INIT(= N_("E275: Cannot add text property to unloaded buffer")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_cannot_use_function_as_method_str[] + INIT(= N_("E276: Cannot use function as a method: %s")); +#endif +#ifdef FEAT_CLIENTSERVER +EXTERN char e_unable_to_read_server_reply[] + INIT(= N_("E277: Unable to read a server reply")); +#endif +// E278 unused +#if defined(FEAT_TERMINAL) && !defined(UNIX) && !defined(MSWIN) +EXTERN char e_sorry_plusplusshell_not_supported_on_this_system[] + INIT(= N_("E279: Sorry, ++shell is not supported on this system")); +#endif +#ifdef FEAT_TCL +EXTERN char e_tcl_fatal_error_reflist_corrupt_please_report_this[] + INIT(= N_("E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim.org")); +#endif +// E281 unused +EXTERN char e_cannot_read_from_str_2[] + INIT(= N_("E282: Cannot read from \"%s\"")); +EXTERN char e_no_marks_matching_str[] + INIT(= N_("E283: No marks matching \"%s\"")); +#ifdef FEAT_XIM +# ifndef FEAT_GUI_GTK +EXTERN char e_cannot_set_ic_values[] + INIT(= N_("E284: Cannot set IC values")); +# endif +# ifdef FEAT_GUI_X11 +EXTERN char e_failed_to_create_input_context[] + INIT(= N_("E285: Failed to create input context")); +EXTERN char e_failed_to_open_input_method[] + INIT(= N_("E286: Failed to open input method")); +EXTERN char e_warning_could_not_set_destroy_callback_to_im[] + INIT(= N_("E287: Warning: Could not set destroy callback to IM")); +EXTERN char e_input_method_doesnt_support_any_style[] + INIT(= N_("E288: Input method doesn't support any style")); +EXTERN char e_input_method_doesnt_support_my_preedit_type[] + INIT(= N_("E289: Input method doesn't support my preedit type")); +# endif +#endif +#ifdef FEAT_SEARCH_EXTRA +EXTERN char e_list_or_number_required[] + INIT(= N_("E290: List or number required")); +#endif +// E291 unused +EXTERN char e_invalid_count_for_del_bytes_nr[] + INIT(= N_("E292: Invalid count for del_bytes(): %ld")); +EXTERN char e_block_was_not_locked[] + INIT(= N_("E293: Block was not locked")); +EXTERN char e_seek_error_in_swap_file_read[] + INIT(= N_("E294: Seek error in swap file read")); +EXTERN char e_read_error_in_swap_file[] + INIT(= N_("E295: Read error in swap file")); +EXTERN char e_seek_error_in_swap_file_write[] + INIT(= N_("E296: Seek error in swap file write")); +EXTERN char e_write_error_in_swap_file[] + INIT(= N_("E297: Write error in swap file")); +EXTERN char e_didnt_get_block_nr_zero[] + INIT(= N_("E298: Didn't get block nr 0?")); +EXTERN char e_didnt_get_block_nr_one[] + INIT(= N_("E298: Didn't get block nr 1?")); +EXTERN char e_didnt_get_block_nr_two[] + INIT(= N_("E298: Didn't get block nr 2?")); +#ifdef FEAT_PERL +EXTERN char e_perl_evaluation_forbidden_in_sandbox_without_safe_module[] + INIT(= N_("E299: Perl evaluation forbidden in sandbox without the Safe module")); +#endif +EXTERN char e_swap_file_already_exists_symlink_attack[] + INIT(= N_("E300: Swap file already exists (symlink attack?)")); +EXTERN char e_oops_lost_the_swap_file[] + INIT(= N_("E301: Oops, lost the swap file!!!")); +EXTERN char e_could_not_rename_swap_file[] + INIT(= N_("E302: Could not rename swap file")); +EXTERN char e_unable_to_open_swap_file_for_str_recovery_impossible[] + INIT(= N_("E303: Unable to open swap file for \"%s\", recovery impossible")); +EXTERN char e_ml_upd_block0_didnt_get_block_zero[] + INIT(= N_("E304: ml_upd_block0(): Didn't get block 0??")); +EXTERN char e_no_swap_file_found_for_str[] + INIT(= N_("E305: No swap file found for %s")); +EXTERN char e_cannot_open_str[] + INIT(= N_("E306: Cannot open %s")); +EXTERN char e_str_does_not_look_like_vim_swap_file[] + INIT(= N_("E307: %s does not look like a Vim swap file")); +EXTERN char e_warning_original_file_may_have_been_changed[] + INIT(= N_("E308: Warning: Original file may have been changed")); +EXTERN char e_unable_to_read_block_one_from_str[] + INIT(= N_("E309: Unable to read block 1 from %s")); +EXTERN char e_block_one_id_wrong_str_not_swp_file[] + INIT(= N_("E310: Block 1 ID wrong (%s not a .swp file?)")); +EXTERN char e_recovery_interrupted[] + INIT(= N_("E311: Recovery Interrupted")); +EXTERN char e_errors_detected_while_recovering_look_for_lines_starting_with_questions[] + INIT(= N_("E312: Errors detected while recovering; look for lines starting with ???")); +EXTERN char e_cannot_preserve_there_is_no_swap_file[] + INIT(= N_("E313: Cannot preserve, there is no swap file")); +EXTERN char e_preserve_failed[] + INIT(= N_("E314: Preserve failed")); +EXTERN char e_ml_get_invalid_lnum_nr[] + INIT(= N_("E315: ml_get: Invalid lnum: %ld")); +EXTERN char e_ml_get_cannot_find_line_nr_in_buffer_nr_str[] + INIT(= N_("E316: ml_get: Cannot find line %ld in buffer %d %s")); +EXTERN char e_pointer_block_id_wrong[] + INIT(= N_("E317: Pointer block id wrong")); +EXTERN char e_pointer_block_id_wrong_two[] + INIT(= N_("E317: Pointer block id wrong 2")); +EXTERN char e_pointer_block_id_wrong_three[] + INIT(= N_("E317: Pointer block id wrong 3")); +EXTERN char e_pointer_block_id_wrong_four[] + INIT(= N_("E317: Pointer block id wrong 4")); +EXTERN char e_updated_too_many_blocks[] + INIT(= N_("E318: Updated too many blocks?")); +EXTERN char e_sorry_command_is_not_available_in_this_version[] + INIT(= N_("E319: Sorry, the command is not available in this version")); +EXTERN char e_cannot_find_line_nr[] + INIT(= N_("E320: Cannot find line %ld")); +EXTERN char e_could_not_reload_str[] + INIT(= N_("E321: Could not reload \"%s\"")); +EXTERN char e_line_number_out_of_range_nr_past_the_end[] + INIT(= N_("E322: Line number out of range: %ld past the end")); +EXTERN char e_line_count_wrong_in_block_nr[] + INIT(= N_("E323: Line count wrong in block %ld")); +#ifdef FEAT_POSTSCRIPT +EXTERN char e_cant_open_postscript_output_file[] + INIT(= N_("E324: Can't open PostScript output file")); +#endif +EXTERN char e_attention[] + INIT(= N_("E325: ATTENTION")); +EXTERN char e_too_many_swap_files_found[] + INIT(= N_("E326: Too many swap files found")); +#ifdef FEAT_MENU +EXTERN char_u e_part_of_menu_item_path_is_not_sub_menu[] + INIT(= N_("E327: Part of menu-item path is not sub-menu")); +EXTERN char e_menu_only_exists_in_another_mode[] + INIT(= N_("E328: Menu only exists in another mode")); +EXTERN char_u e_no_menu_str[] + INIT(= N_("E329: No menu \"%s\"")); +EXTERN char e_menu_path_must_not_lead_to_sub_menu[] + INIT(= N_("E330: Menu path must not lead to a sub-menu")); +EXTERN char e_must_not_add_menu_items_directly_to_menu_bar[] + INIT(= N_("E331: Must not add menu items directly to menu bar")); +EXTERN char e_separator_cannot_be_part_of_menu_path[] + INIT(= N_("E332: Separator cannot be part of a menu path")); +EXTERN char e_menu_path_must_lead_to_menu_item[] + INIT(= N_("E333: Menu path must lead to a menu item")); +EXTERN char e_menu_not_found_str[] + INIT(= N_("E334: Menu not found: %s")); +EXTERN char e_menu_not_defined_for_str_mode[] + INIT(= N_("E335: Menu not defined for %s mode")); +EXTERN char e_menu_path_must_lead_to_sub_menu[] + INIT(= N_("E336: Menu path must lead to a sub-menu")); +EXTERN char e_menu_not_found_check_menu_names[] + INIT(= N_("E337: Menu not found - check menu names")); +#endif +#ifdef FEAT_BROWSE +EXTERN char e_sorry_no_file_browser_in_console_mode[] + INIT(= N_("E338: Sorry, no file browser in console mode")); +#endif +EXTERN char e_pattern_too_long[] + INIT(= N_("E339: Pattern too long")); +// E340 unused +EXTERN char e_internal_error_lalloc_zero[] + INIT(= N_("E341: Internal error: lalloc(0, )")); +EXTERN char e_out_of_memory_allocating_nr_bytes[] + INIT(= N_("E342: Out of memory! (allocating %lu bytes)")); +EXTERN char e_invalid_path_number_must_be_at_end_of_path_or_be_followed_by_str[] + INIT(= N_("E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'.")); +EXTERN char e_cant_find_directory_str_in_cdpath[] + INIT(= N_("E344: Can't find directory \"%s\" in cdpath")); +EXTERN char e_cant_find_file_str_in_path[] + INIT(= N_("E345: Can't find file \"%s\" in path")); +EXTERN char e_no_more_directory_str_found_in_cdpath[] + INIT(= N_("E346: No more directory \"%s\" found in cdpath")); +EXTERN char e_no_more_file_str_found_in_path[] + INIT(= N_("E347: No more file \"%s\" found in path")); +EXTERN char e_no_string_under_cursor[] + INIT(= N_("E348: No string under cursor")); +EXTERN char e_no_identifier_under_cursor[] + INIT(= N_("E349: No identifier under cursor")); +#ifdef FEAT_FOLDING +EXTERN char e_cannot_create_fold_with_current_foldmethod[] + INIT(= N_("E350: Cannot create fold with current 'foldmethod'")); +EXTERN char e_cannot_delete_fold_with_current_foldmethod[] + INIT(= N_("E351: Cannot delete fold with current 'foldmethod'")); +EXTERN char e_cannot_erase_folds_with_current_foldmethod[] + INIT(= N_("E352: Cannot erase folds with current 'foldmethod'")); +#endif +EXTERN char e_nothing_in_register_str[] + INIT(= N_("E353: Nothing in register %s")); +EXTERN char e_invalid_register_name_str[] + INIT(= N_("E354: Invalid register name: '%s'")); +EXTERN char e_unknown_option_str_2[] + INIT(= N_("E355: Unknown option: %s")); +EXTERN char e_get_varp_error[] + INIT(= N_("E356: get_varp ERROR")); +#ifdef FEAT_LANGMAP +EXTERN char e_langmap_matching_character_missing_for_str[] + INIT(= N_("E357: 'langmap': Matching character missing for %s")); +EXTERN char e_langmap_extra_characters_after_semicolon_str[] + INIT(= N_("E358: 'langmap': Extra characters after semicolon: %s")); +#endif +#if defined(AMIGA) || defined(MACOS_X) || defined(MSWIN) \ + || defined(UNIX) || defined(VMS) +EXTERN char e_screen_mode_setting_not_supported[] + INIT(= N_("E359: Screen mode setting not supported")); +#endif +#ifdef AMIGA +EXTERN char e_cannot_execute_shell_with_f_option[] + INIT(= N_("E360: Cannot execute shell with -f option")); +#endif +// E361 unused +#if defined(FEAT_EVAL) +EXTERN char e_using_boolean_value_as_float[] + INIT(= N_("E362: Using a boolean value as a Float")); +#endif +EXTERN char e_pattern_uses_more_memory_than_maxmempattern[] + INIT(= N_("E363: Pattern uses more memory than 'maxmempattern'")); +#ifdef FEAT_LIBCALL +EXTERN char e_library_call_failed_for_str[] + INIT(= N_("E364: Library call failed for \"%s()\"")); +#endif +#ifdef FEAT_POSTSCRIPT +EXTERN char e_failed_to_print_postscript_file[] + INIT(= N_("E365: Failed to print PostScript file")); +#endif +#ifdef FEAT_PROP_POPUP +EXTERN char e_not_allowed_to_enter_popup_window[] + INIT(= N_("E366: Not allowed to enter a popup window")); +#endif +EXTERN char e_no_such_group_str[] + INIT(= N_("E367: No such group: \"%s\"")); +#ifdef FEAT_LIBCALL +EXTERN char e_got_sig_str_in_libcall[] + INIT(= N_("E368: Got SIG%s in libcall()")); +#endif +EXTERN char e_invalid_item_in_str_brackets[] + INIT(= N_("E369: Invalid item in %s%%[]")); +#ifdef USING_LOAD_LIBRARY +EXTERN char e_could_not_load_library_str_str[] + INIT(= N_("E370: Could not load library %s: %s")); +#endif +#ifdef FEAT_GUI_MSWIN +EXTERN char e_command_not_found[] + INIT(= N_("E371: Command not found")); +#endif +#ifdef FEAT_QUICKFIX +EXTERN char e_too_many_chr_in_format_string[] + INIT(= N_("E372: Too many %%%c in format string")); +EXTERN char e_unexpected_chr_in_format_str[] + INIT(= N_("E373: Unexpected %%%c in format string")); +EXTERN char e_missing_rsb_in_format_string[] + INIT(= N_("E374: Missing ] in format string")); +EXTERN char e_unsupported_chr_in_format_string[] + INIT(= N_("E375: Unsupported %%%c in format string")); +EXTERN char e_invalid_chr_in_format_string_prefix[] + INIT(= N_("E376: Invalid %%%c in format string prefix")); +EXTERN char e_invalid_chr_in_format_string[] + INIT(= N_("E377: Invalid %%%c in format string")); +EXTERN char e_errorformat_contains_no_pattern[] + INIT(= N_("E378: 'errorformat' contains no pattern")); +EXTERN char e_missing_or_empty_directory_name[] + INIT(= N_("E379: Missing or empty directory name")); +EXTERN char e_at_bottom_of_quickfix_stack[] + INIT(= N_("E380: At bottom of quickfix stack")); +EXTERN char e_at_top_of_quickfix_stack[] + INIT(= N_("E381: At top of quickfix stack")); +#endif +EXTERN char e_cannot_write_buftype_option_is_set[] + INIT(= N_("E382: Cannot write, 'buftype' option is set")); +EXTERN char e_invalid_search_string_str[] + INIT(= N_("E383: Invalid search string: %s")); +EXTERN char e_search_hit_top_without_match_for_str[] + INIT(= N_("E384: Search hit TOP without match for: %s")); +EXTERN char e_search_hit_bottom_without_match_for_str[] + INIT(= N_("E385: Search hit BOTTOM without match for: %s")); +EXTERN char e_expected_question_or_slash_after_semicolon[] + INIT(= N_("E386: Expected '?' or '/' after ';'")); +#ifdef FEAT_FIND_ID +EXTERN char e_match_is_on_current_line[] + INIT(= N_("E387: Match is on current line")); +EXTERN char e_couldnt_find_definition[] + INIT(= N_("E388: Couldn't find definition")); +EXTERN char e_couldnt_find_pattern[] + INIT(= N_("E389: Couldn't find pattern")); +#endif +#ifdef FEAT_SYN_HL +EXTERN char e_illegal_argument_str_2[] + INIT(= N_("E390: Illegal argument: %s")); +EXTERN char e_no_such_syntax_cluster_str_1[] + INIT(= N_("E391: No such syntax cluster: %s")); +EXTERN char e_no_such_syntax_cluster_str_2[] + INIT(= N_("E392: No such syntax cluster: %s")); +EXTERN char e_groupthere_not_accepted_here[] + INIT(= N_("E393: group[t]here not accepted here")); +EXTERN char e_didnt_find_region_item_for_str[] + INIT(= N_("E394: Didn't find region item for %s")); +EXTERN char e_contains_argument_not_accepted_here[] + INIT(= N_("E395: Contains argument not accepted here")); +// E396 unused +EXTERN char e_filename_required[] + INIT(= N_("E397: Filename required")); +EXTERN char e_missing_equal_str[] + INIT(= N_("E398: Missing '=': %s")); +EXTERN char e_not_enough_arguments_syntax_region_str[] + INIT(= N_("E399: Not enough arguments: syntax region %s")); +EXTERN char e_no_cluster_specified[] + INIT(= N_("E400: No cluster specified")); +EXTERN char e_pattern_delimiter_not_found_str[] + INIT(= N_("E401: Pattern delimiter not found: %s")); +EXTERN char e_garbage_after_pattern_str[] + INIT(= N_("E402: Garbage after pattern: %s")); +EXTERN char e_syntax_sync_line_continuations_pattern_specified_twice[] + INIT(= N_("E403: syntax sync: Line continuations pattern specified twice")); +EXTERN char e_illegal_arguments_str[] + INIT(= N_("E404: Illegal arguments: %s")); +EXTERN char e_missing_equal_sign_str[] + INIT(= N_("E405: Missing equal sign: %s")); +EXTERN char e_empty_argument_str[] + INIT(= N_("E406: Empty argument: %s")); +EXTERN char e_str_not_allowed_here[] + INIT(= N_("E407: %s not allowed here")); +EXTERN char e_str_must_be_first_in_contains_list[] + INIT(= N_("E408: %s must be first in contains list")); +EXTERN char e_unknown_group_name_str[] + INIT(= N_("E409: Unknown group name: %s")); +EXTERN char e_invalid_syntax_subcommand_str[] + INIT(= N_("E410: Invalid :syntax subcommand: %s")); +#endif +EXTERN char e_highlight_group_name_not_found_str[] + INIT(= N_("E411: Highlight group not found: %s")); +EXTERN char e_not_enough_arguments_highlight_link_str[] + INIT(= N_("E412: Not enough arguments: \":highlight link %s\"")); +EXTERN char e_too_many_arguments_highlight_link_str[] + INIT(= N_("E413: Too many arguments: \":highlight link %s\"")); +EXTERN char e_group_has_settings_highlight_link_ignored[] + INIT(= N_("E414: Group has settings, highlight link ignored")); +EXTERN char e_unexpected_equal_sign_str[] + INIT(= N_("E415: Unexpected equal sign: %s")); +EXTERN char e_missing_equal_sign_str_2[] + INIT(= N_("E416: Missing equal sign: %s")); +EXTERN char e_missing_argument_str[] + INIT(= N_("E417: Missing argument: %s")); +EXTERN char e_illegal_value_str[] + INIT(= N_("E418: Illegal value: %s")); +EXTERN char e_fg_color_unknown[] + INIT(= N_("E419: FG color unknown")); +EXTERN char e_bg_color_unknown[] + INIT(= N_("E420: BG color unknown")); +EXTERN char e_color_name_or_number_not_recognized_str[] + INIT(= N_("E421: Color name or number not recognized: %s")); +EXTERN char e_terminal_code_too_long_str[] + INIT(= N_("E422: Terminal code too long: %s")); +EXTERN char e_illegal_argument_str_3[] + INIT(= N_("E423: Illegal argument: %s")); +EXTERN char e_too_many_different_highlighting_attributes_in_use[] + INIT(= N_("E424: Too many different highlighting attributes in use")); +EXTERN char e_cannot_go_before_first_matching_tag[] + INIT(= N_("E425: Cannot go before first matching tag")); +EXTERN char e_tag_not_found_str[] + INIT(= N_("E426: Tag not found: %s")); +EXTERN char e_there_is_only_one_matching_tag[] + INIT(= N_("E427: There is only one matching tag")); +EXTERN char e_cannot_go_beyond_last_matching_tag[] + INIT(= N_("E428: Cannot go beyond last matching tag")); +EXTERN char e_file_str_does_not_exist[] + INIT(= N_("E429: File \"%s\" does not exist")); +#ifdef FEAT_EMACS_TAGS +EXTERN char e_tag_file_path_truncated_for_str[] + INIT(= N_("E430: Tag file path truncated for %s\n")); +#endif +EXTERN char e_format_error_in_tags_file_str[] + INIT(= N_("E431: Format error in tags file \"%s\"")); +EXTERN char e_tags_file_not_sorted_str[] + INIT(= N_("E432: Tags file not sorted: %s")); +EXTERN char e_no_tags_file[] + INIT(= N_("E433: No tags file")); +EXTERN char e_cannot_find_tag_pattern[] + INIT(= N_("E434: Can't find tag pattern")); +EXTERN char e_couldnt_find_tag_just_guessing[] + INIT(= N_("E435: Couldn't find tag, just guessing!")); +EXTERN char e_no_str_entry_in_termcap[] + INIT(= N_("E436: No \"%s\" entry in termcap")); +EXTERN char e_terminal_capability_cm_required[] + INIT(= N_("E437: Terminal capability \"cm\" required")); +EXTERN char e_u_undo_line_numbers_wrong[] + INIT(= N_("E438: u_undo: Line numbers wrong")); +EXTERN char e_undo_list_corrupt[] + INIT(= N_("E439: Undo list corrupt")); +EXTERN char e_undo_line_missing[] + INIT(= N_("E440: Undo line missing")); +#ifdef FEAT_QUICKFIX +EXTERN char e_there_is_no_preview_window[] + INIT(= N_("E441: There is no preview window")); +#endif +EXTERN char e_cant_split_topleft_and_botright_at_the_same_time[] + INIT(= N_("E442: Can't split topleft and botright at the same time")); +EXTERN char e_cannot_rotate_when_another_window_is_split[] + INIT(= N_("E443: Cannot rotate when another window is split")); +EXTERN char e_cannot_close_last_window[] + INIT(= N_("E444: Cannot close last window")); +EXTERN char e_other_window_contains_changes[] + INIT(= N_("E445: Other window contains changes")); +EXTERN char e_no_file_name_under_cursor[] + INIT(= N_("E446: No file name under cursor")); +EXTERN char e_cant_find_file_str_in_path_2[] + INIT(= N_("E447: Can't find file \"%s\" in path")); +#ifdef USING_LOAD_LIBRARY +EXTERN char e_could_not_load_library_function_str[] + INIT(= N_("E448: Could not load library function %s")); +#endif +#ifdef FEAT_CLIENTSERVER +EXTERN char e_invalid_expression_received[] + INIT(= N_("E449: Invalid expression received")); +#endif +#ifdef FEAT_PROP_POPUP +EXTERN char e_buffer_number_text_or_list_required[] + INIT(= N_("E450: Buffer number, text or a list required")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_expected_right_curly_str[] + INIT(= N_("E451: Expected }: %s")); +EXTERN char e_double_semicolon_in_list_of_variables[] + INIT(= N_("E452: Double ; in list of variables")); +#endif +EXTERN char e_ul_color_unknown[] + INIT(= N_("E453: UL color unknown")); +#ifdef FEAT_EVAL +EXTERN char e_function_list_was_modified[] + INIT(= N_("E454: Function list was modified")); +#endif +#ifdef FEAT_POSTSCRIPT +EXTERN char e_error_writing_to_postscript_output_file[] + INIT(= N_("E455: Error writing to PostScript output file")); +EXTERN char e_cant_open_file_str_2[] + INIT(= N_("E456: Can't open file \"%s\"")); +EXTERN char e_cant_find_postscript_resource_file_str_ps[] + INIT(= N_("E456: Can't find PostScript resource file \"%s.ps\"")); +EXTERN char e_cant_read_postscript_resource_file_str[] + INIT(= N_("E457: Can't read PostScript resource file \"%s\"")); +#endif +#ifdef FEAT_GUI_X11 +EXTERN char e_cannot_allocate_colormap_entry_some_colors_may_be_incorrect[] + INIT(= N_("E458: Cannot allocate colormap entry, some colors may be incorrect")); +#endif +#if defined(UNIX) || defined(FEAT_SESSION) +EXTERN char e_cannot_go_back_to_previous_directory[] + INIT(= N_("E459: Cannot go back to previous directory")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_entries_missing_in_mapset_dict_argument[] + INIT(= N_("E460: Entries missing in mapset() dict argument")); +EXTERN char e_illegal_variable_name_str[] + INIT(= N_("E461: Illegal variable name: %s")); +#endif +EXTERN char e_could_not_prepare_for_reloading_str[] + INIT(= N_("E462: Could not prepare for reloading \"%s\"")); +#ifdef FEAT_NETBEANS_INTG +EXTERN char e_region_is_guarded_cannot_modify[] + INIT(= N_("E463: Region is guarded, cannot modify")); +#endif +EXTERN char e_ambiguous_use_of_user_defined_command[] + INIT(= N_("E464: Ambiguous use of user-defined command")); +#ifdef FEAT_EVAL +EXTERN char e_ambiguous_use_of_user_defined_command_str[] + INIT(= N_("E464: Ambiguous use of user-defined command: %s")); +#endif +EXTERN char e_winsize_requires_two_number_arguments[] + INIT(= N_("E465: :winsize requires two number arguments")); +EXTERN char e_winpos_requires_two_number_arguments[] + INIT(= N_("E466: :winpos requires two number arguments")); +#ifdef FEAT_EVAL +EXTERN char e_custom_completion_requires_function_argument[] + INIT(= N_("E467: Custom completion requires a function argument")); +#endif +EXTERN char e_completion_argument_only_allowed_for_custom_completion[] + INIT(= N_("E468: Completion argument only allowed for custom completion")); +#ifdef FEAT_CSCOPE +EXTERN char e_invalid_cscopequickfix_flag_chr_for_chr[] + INIT(= N_("E469: Invalid cscopequickfix flag %c for %c")); +#endif +EXTERN char e_command_aborted[] + INIT(= N_("E470: Command aborted")); +EXTERN char e_argument_required[] + INIT(= N_("E471: Argument required")); +EXTERN char e_command_failed[] + INIT(= N_("E472: Command failed")); +EXTERN char e_internal_error_in_regexp[] + INIT(= N_("E473: Internal error in regexp")); +EXTERN char e_invalid_argument[] + INIT(= N_("E474: Invalid argument")); +EXTERN char e_invalid_argument_str[] + INIT(= N_("E475: Invalid argument: %s")); +EXTERN char e_invalid_value_for_argument_str[] + INIT(= N_("E475: Invalid value for argument %s")); +#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_PROP_POPUP) || defined(FEAT_EVAL) +EXTERN char e_invalid_value_for_argument_str_str[] + INIT(= N_("E475: Invalid value for argument %s: %s")); +#endif +EXTERN char e_invalid_command[] + INIT(= N_("E476: Invalid command")); +EXTERN char e_invalid_command_str[] + INIT(= N_("E476: Invalid command: %s")); +EXTERN char e_invalid_command_str_expected_str[] + INIT(= N_("E476: Invalid command: %s, expected %s")); +EXTERN char e_no_bang_allowed[] + INIT(= N_("E477: No ! allowed")); +EXTERN char e_dont_panic[] + INIT(= N_("E478: Don't panic!")); +EXTERN char e_no_match[] + INIT(= N_("E479: No match")); +EXTERN char e_no_match_str_2[] + INIT(= N_("E480: No match: %s")); +EXTERN char e_no_range_allowed[] + INIT(= N_("E481: No range allowed")); +EXTERN char e_cant_create_file_str[] + INIT(= N_("E482: Can't create file %s")); +EXTERN char e_cant_get_temp_file_name[] + INIT(= N_("E483: Can't get temp file name")); +EXTERN char e_cant_open_file_str[] + INIT(= N_("E484: Can't open file %s")); +EXTERN char e_cant_read_file_str[] + INIT(= N_("E485: Can't read file %s")); +EXTERN char e_pattern_not_found[] + INIT(= N_("E486: Pattern not found")); +EXTERN char e_pattern_not_found_str[] + INIT(= N_("E486: Pattern not found: %s")); +EXTERN char e_argument_must_be_positive[] + INIT(= N_("E487: Argument must be positive")); +EXTERN char e_argument_must_be_positive_str[] + INIT(= N_("E487: Argument must be positive: %s")); +EXTERN char e_trailing_characters[] + INIT(= N_("E488: Trailing characters")); +EXTERN char e_trailing_characters_str[] + INIT(= N_("E488: Trailing characters: %s")); +EXTERN char e_no_call_stack_to_substitute_for_stack[] + INIT(= N_("E489: No call stack to substitute for \"\"")); +#ifdef FEAT_FOLDING +EXTERN char e_no_fold_found[] + INIT(= N_("E490: No fold found")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_json_decode_error_at_str[] + INIT(= N_("E491: JSON decode error at '%s'")); +#endif +EXTERN char e_not_an_editor_command[] + INIT(= N_("E492: Not an editor command")); +EXTERN char e_backwards_range_given[] + INIT(= N_("E493: Backwards range given")); +EXTERN char e_use_w_or_w_gt_gt[] + INIT(= N_("E494: Use w or w>>")); +EXTERN char e_no_autocommand_file_name_to_substitute_for_afile[] + INIT(= N_("E495: No autocommand file name to substitute for \"\"")); +EXTERN char e_no_autocommand_buffer_name_to_substitute_for_abuf[] + INIT(= N_("E496: No autocommand buffer number to substitute for \"\"")); +EXTERN char e_no_autocommand_match_name_to_substitute_for_amatch[] + INIT(= N_("E497: No autocommand match name to substitute for \"\"")); +EXTERN char e_no_source_file_name_to_substitute_for_sfile[] + INIT(= N_("E498: No :source file name to substitute for \"\"")); +EXTERN char e_empty_file_name_for_percent_or_hash_only_works_with_ph[] + // xgettext:no-c-format + INIT(= N_("E499: Empty file name for '%' or '#', only works with \":p:h\"")); +EXTERN char e_evaluates_to_an_empty_string[] + INIT(= N_("E500: Evaluates to an empty string")); +EXTERN char e_at_end_of_file[] + INIT(= N_("E501: At end-of-file")); + // E502 +EXTERN char e_is_a_directory[] + INIT(= N_("is a directory")); + // E503 +EXTERN char e_is_not_file_or_writable_device[] + INIT(= N_("is not a file or writable device")); +EXTERN char e_str_is_not_file_or_writable_device[] + INIT(= N_("E503: \"%s\" is not a file or writable device")); + // E504 +EXTERN char e_is_read_only_cannot_override_W_in_cpoptions[] + INIT(= N_("is read-only (cannot override: \"W\" in 'cpoptions')")); + // E505 +EXTERN char e_is_read_only_add_bang_to_override[] + INIT(= N_("is read-only (add ! to override)")); +EXTERN char e_str_is_read_only_add_bang_to_override[] + INIT(= N_("E505: \"%s\" is read-only (add ! to override)")); +EXTERN char e_cant_write_to_backup_file_add_bang_to_override[] + INIT(= N_("E506: Can't write to backup file (add ! to override)")); +EXTERN char e_close_error_for_backup_file_add_bang_to_write_anyway[] + INIT(= N_("E507: Close error for backup file (add ! to write anyway)")); +EXTERN char e_cant_read_file_for_backup_add_bang_to_write_anyway[] + INIT(= N_("E508: Can't read file for backup (add ! to write anyway)")); +EXTERN char e_cannot_create_backup_file_add_bang_to_write_anyway[] + INIT(= N_("E509: Cannot create backup file (add ! to override)")); +EXTERN char e_cant_make_backup_file_add_bang_to_write_anyway[] + INIT(= N_("E510: Can't make backup file (add ! to write anyway)")); +#ifdef FEAT_NETBEANS_INTG +EXTERN char e_netbeans_already_connected[] + INIT(= N_("E511: NetBeans already connected")); +#endif +EXTERN char e_close_failed[] + INIT(= N_("E512: Close failed")); +EXTERN char e_write_error_conversion_failed_make_fenc_empty_to_override[] + INIT(= N_("E513: Write error, conversion failed (make 'fenc' empty to override)")); +EXTERN char e_write_error_conversion_failed_in_line_nr_make_fenc_empty_to_override[] + INIT(= N_("E513: Write error, conversion failed in line %ld (make 'fenc' empty to override)")); +EXTERN char e_write_error_file_system_full[] + INIT(= N_("E514: Write error (file system full?)")); +EXTERN char e_no_buffers_were_unloaded[] + INIT(= N_("E515: No buffers were unloaded")); +EXTERN char e_no_buffers_were_deleted[] + INIT(= N_("E516: No buffers were deleted")); +EXTERN char e_no_buffers_were_wiped_out[] + INIT(= N_("E517: No buffers were wiped out")); +EXTERN char e_unknown_option[] + INIT(= N_("E518: Unknown option")); +EXTERN char e_option_not_supported[] + INIT(= N_("E519: Option not supported")); +EXTERN char e_not_allowed_in_modeline[] + INIT(= N_("E520: Not allowed in a modeline")); +EXTERN char e_number_required_after_equal[] + INIT(= N_("E521: Number required after =")); +EXTERN char e_number_required_after_str_equal_str[] + INIT(= N_("E521: Number required: &%s = '%s'")); +EXTERN char e_not_found_in_termcap[] + INIT(= N_("E522: Not found in termcap")); +EXTERN char e_not_allowed_here[] + INIT(= N_("E523: Not allowed here")); +EXTERN char e_missing_colon[] + INIT(= N_("E524: Missing colon")); +EXTERN char e_zero_length_string[] + INIT(= N_("E525: Zero length string")); +#ifdef FEAT_VIMINFO +EXTERN char e_missing_number_after_angle_str_angle[] + INIT(= N_("E526: Missing number after <%s>")); +EXTERN char e_missing_comma[] + INIT(= N_("E527: Missing comma")); +EXTERN char e_must_specify_a_value[] + INIT(= N_("E528: Must specify a ' value")); +#endif +EXTERN char e_cannot_set_term_to_empty_string[] + INIT(= N_("E529: Cannot set 'term' to empty string")); +#ifdef FEAT_GUI +EXTERN char e_cannot_change_term_in_GUI[] + INIT(= N_("E530: Cannot change 'term' in the GUI")); +EXTERN char e_use_gui_to_start_GUI[] + INIT(= N_("E531: Use \":gui\" to start the GUI")); +#endif +#ifdef FEAT_NETBEANS_INTG +EXTERN char e_highlighting_color_name_too_long_in_defineAnnoType[] + INIT(= N_("E532: Highlighting color name too long in defineAnnoType")); +#endif +#ifdef FEAT_GUI +EXTERN char e_cant_select_wide_font[] + INIT(= N_("E533: Can't select wide font")); +EXTERN char e_invalid_wide_font[] + INIT(= N_("E534: Invalid wide font")); +#endif +EXTERN char e_illegal_character_after_chr[] + INIT(= N_("E535: Illegal character after <%c>")); +#ifdef FEAT_FOLDING +EXTERN char e_comma_required[] + INIT(= N_("E536: Comma required")); +EXTERN char e_commentstring_must_be_empty_or_contain_str[] + INIT(= N_("E537: 'commentstring' must be empty or contain %s")); +#endif +EXTERN char e_pattern_found_in_every_line_str[] + INIT(= N_("E538: Pattern found in every line: %s")); +EXTERN char e_illegal_character_str[] + INIT(= N_("E539: Illegal character <%s>")); +#ifdef FEAT_STL_OPT +EXTERN char e_unclosed_expression_sequence[] + INIT(= N_("E540: Unclosed expression sequence")); +// E541 unused +EXTERN char e_unbalanced_groups[] + INIT(= N_("E542: Unbalanced groups")); +#endif +#ifdef MSWIN +EXTERN char e_not_valid_codepage[] + INIT(= N_("E543: Not a valid codepage")); +#endif +#ifdef FEAT_KEYMAP +EXTERN char e_keymap_file_not_found[] + INIT(= N_("E544: Keymap file not found")); +#endif +#ifdef CURSOR_SHAPE +EXTERN char e_missing_colon_2[] + INIT(= N_("E545: Missing colon")); +EXTERN char e_illegal_mode[] + INIT(= N_("E546: Illegal mode")); +#endif +#ifdef FEAT_MOUSESHAPE +EXTERN char e_illegal_mouseshape[] + INIT(= N_("E547: Illegal mouseshape")); +#endif +EXTERN char e_digit_expected[] + INIT(= N_("E548: Digit expected")); +EXTERN char e_illegal_percentage[] + INIT(= N_("E549: Illegal percentage")); +#ifdef FEAT_PRINTER +EXTERN char e_missing_colon_3[] + INIT(= N_("E550: Missing colon")); +EXTERN char e_illegal_component[] + INIT(= N_("E551: Illegal component")); +EXTERN char e_digit_expected_2[] + INIT(= N_("E552: Digit expected")); +#endif +#ifdef FEAT_QUICKFIX +EXTERN char e_no_more_items[] + INIT(= N_("E553: No more items")); +#endif +EXTERN char e_syntax_error_in_str_curlies[] + INIT(= N_("E554: Syntax error in %s{...}")); +EXTERN char e_at_bottom_of_tag_stack[] + INIT(= N_("E555: At bottom of tag stack")); +EXTERN char e_at_top_of_tag_stack[] + INIT(= N_("E556: At top of tag stack")); +EXTERN char e_cannot_open_termcap_file[] + INIT(= N_("E557: Cannot open termcap file")); +EXTERN char e_terminal_entry_not_found_in_terminfo[] + INIT(= N_("E558: Terminal entry not found in terminfo")); +#if defined(HAVE_TGETENT) && !defined(TERMINFO) +EXTERN char e_terminal_entry_not_found_in_termcap[] + INIT(= N_("E559: Terminal entry not found in termcap")); +#endif +#ifdef FEAT_CSCOPE +EXTERN char e_usage_cscope_str[] + INIT(= N_("E560: Usage: cs[cope] %s")); +EXTERN char e_unknown_cscope_search_type[] + INIT(= N_("E561: Unknown cscope search type")); +EXTERN char e_usage_cstag_ident[] + INIT(= N_("E562: Usage: cstag ")); +EXTERN char e_stat_str_error_nr[] + INIT(= N_("E563: stat(%s) error: %d")); +EXTERN char e_str_is_not_directory_or_valid_cscope_database[] + INIT(= N_("E564: %s is not a directory or a valid cscope database")); +#endif +EXTERN char e_not_allowed_to_change_text_or_change_window[] + INIT(= N_("E565: Not allowed to change text or change window")); +#ifdef FEAT_CSCOPE +EXTERN char e_could_not_create_cscope_pipes[] + INIT(= N_("E566: Could not create cscope pipes")); +EXTERN char e_no_cscope_connections[] + INIT(= N_("E567: No cscope connections")); +EXTERN char e_duplicate_cscope_database_not_added[] + INIT(= N_("E568: Duplicate cscope database not added")); +// E569 unused +EXTERN char e_fatal_error_in_cs_manage_matches[] + INIT(= N_("E570: Fatal error in cs_manage_matches")); +#endif +#ifdef DYNAMIC_TCL +EXTERN char e_sorry_this_command_is_disabled_tcl_library_could_not_be_loaded[] + INIT(= N_("E571: Sorry, this command is disabled: the Tcl library could not be loaded.")); +#endif +#ifdef FEAT_TCL +EXTERN char e_exit_code_nr[] + INIT(= N_("E572: Exit code %d")); +#endif +#ifdef FEAT_CLIENTSERVER +EXTERN char e_invalid_server_id_used_str[] + INIT(= N_("E573: Invalid server id used: %s")); +#endif +#ifdef FEAT_VIMINFO +EXTERN char e_unknown_register_type_nr[] + INIT(= N_("E574: Unknown register type %d")); + // E575 +EXTERN char e_illegal_starting_char[] + INIT(= N_("Illegal starting char")); + // E576 +EXTERN char e_nonr_missing_gt[] + INIT(= N_("Missing '>'")); + // E577 +EXTERN char e_illegal_register_name[] + INIT(= N_("Illegal register name")); +#endif +// E578 unused +#ifdef FEAT_EVAL +EXTERN char e_if_nesting_too_deep[] + INIT(= N_("E579: :if nesting too deep")); +EXTERN char e_block_nesting_too_deep[] + INIT(= N_("E579: Block nesting too deep")); +EXTERN char e_endif_without_if[] + INIT(= N_("E580: :endif without :if")); +EXTERN char e_else_without_if[] + INIT(= N_("E581: :else without :if")); +EXTERN char e_elseif_without_if[] + INIT(= N_("E582: :elseif without :if")); +EXTERN char e_multiple_else[] + INIT(= N_("E583: Multiple :else")); +EXTERN char e_elseif_after_else[] + INIT(= N_("E584: :elseif after :else")); +EXTERN char e_while_for_nesting_too_deep[] + INIT(= N_("E585: :while/:for nesting too deep")); +EXTERN char e_continue_without_while_or_for[] + INIT(= N_("E586: :continue without :while or :for")); +EXTERN char e_break_without_while_or_for[] + INIT(= N_("E587: :break without :while or :for")); +EXTERN char e_endwhile_without_while[] + INIT(= N_("E588: :endwhile without :while")); +EXTERN char e_endfor_without_for[] + INIT(= N_("E588: :endfor without :for")); +#endif +EXTERN char e_backupext_and_patchmode_are_equal[] + INIT(= N_("E589: 'backupext' and 'patchmode' are equal")); +#ifdef FEAT_QUICKFIX +EXTERN char e_preview_window_already_exists[] + INIT(= N_("E590: A preview window already exists")); +#endif +EXTERN char e_winheight_cannot_be_smaller_than_winminheight[] + INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'")); +EXTERN char e_winwidth_cannot_be_smaller_than_winminwidth[] + INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'")); +EXTERN char e_need_at_least_nr_lines[] + INIT(= N_("E593: Need at least %d lines")); +EXTERN char e_need_at_least_nr_columns[] + INIT(= N_("E594: Need at least %d columns")); +#ifdef FEAT_LINEBREAK +EXTERN char e_showbreak_contains_unprintable_or_wide_character[] + INIT(= N_("E595: 'showbreak' contains unprintable or wide character")); +#endif +#ifdef FEAT_GUI +EXTERN char e_invalid_fonts[] + INIT(= N_("E596: Invalid font(s)")); +# ifdef FEAT_XFONTSET +EXTERN char e_cant_select_fontset[] + INIT(= N_("E597: Can't select fontset")); +EXTERN char e_invalid_fontset[] + INIT(= N_("E598: Invalid fontset")); +# endif +#endif +#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) +EXTERN char e_value_of_imactivatekey_is_invalid[] + INIT(= N_("E599: Value of 'imactivatekey' is invalid")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_missing_endtry[] + INIT(= N_("E600: Missing :endtry")); +EXTERN char e_try_nesting_too_deep[] + INIT(= N_("E601: :try nesting too deep")); +EXTERN char e_endtry_without_try[] + INIT(= N_("E602: :endtry without :try")); +EXTERN char e_catch_without_try[] + INIT(= N_("E603: :catch without :try")); +EXTERN char e_catch_after_finally[] + INIT(= N_("E604: :catch after :finally")); +EXTERN char e_exception_not_caught_str[] + INIT(= N_("E605: Exception not caught: %s")); +EXTERN char e_finally_without_try[] + INIT(= N_("E606: :finally without :try")); +EXTERN char e_multiple_finally[] + INIT(= N_("E607: Multiple :finally")); +EXTERN char e_cannot_throw_exceptions_with_vim_prefix[] + INIT(= N_("E608: Cannot :throw exceptions with 'Vim' prefix")); +#endif +#ifdef FEAT_CSCOPE +EXTERN char e_cscope_error_str[] + INIT(= N_("E609: Cscope error: %s")); +#endif +EXTERN char e_no_argument_to_delete[] + INIT(= N_("E610: No argument to delete")); +#ifdef FEAT_EVAL +EXTERN char e_using_special_as_number[] + INIT(= N_("E611: Using a Special as a Number")); +#endif +#ifdef FEAT_SIGNS +EXTERN char e_too_many_signs_defined[] + INIT(= N_("E612: Too many signs defined")); +#endif +#if defined(MSWIN) && defined(FEAT_PRINTER) +EXTERN char e_unknown_printer_font_str[] + INIT(= N_("E613: Unknown printer font: %s")); +#endif +// E614 unused +// E615 unused +// E616 unused +#ifdef FEAT_GUI_GTK +EXTERN char e_cannot_be_changed_in_gtk_GUI[] + INIT(= N_("E617: Cannot be changed in the GTK GUI")); +#endif +#ifdef FEAT_POSTSCRIPT +EXTERN char e_file_str_is_not_postscript_resource_file[] + INIT(= N_("E618: File \"%s\" is not a PostScript resource file")); +EXTERN char e_file_str_is_not_supported_postscript_resource_file[] + INIT(= N_("E619: File \"%s\" is not a supported PostScript resource file")); +EXTERN char e_unable_to_convert_to_print_encoding_str[] + INIT(= N_("E620: Unable to convert to print encoding \"%s\"")); +EXTERN char e_str_resource_file_has_wrong_version[] + INIT(= N_("E621: \"%s\" resource file has wrong version")); +#endif +#ifdef FEAT_CSCOPE +EXTERN char e_could_not_fork_for_cscope[] + INIT(= N_("E622: Could not fork for cscope")); +# ifndef UNIX +EXTERN char e_could_not_spawn_cscope_process[] + INIT(= N_("E623: Could not spawn cscope process")); +# endif +#endif +#if defined(FEAT_PRINTER) && defined(FEAT_POSTSCRIPT) +EXTERN char e_cant_open_file_str_3[] + INIT(= N_("E624: Can't open file \"%s\"")); +#endif +#if defined(FEAT_CSCOPE) && !defined(UNIX) +EXTERN char e_cannot_open_cscope_database_str[] + INIT(= N_("E625: Cannot open cscope database: %s")); +EXTERN char e_cannot_get_cscope_database_information[] + INIT(= N_("E626: Cannot get cscope database information")); +#endif +#ifdef FEAT_NETBEANS_INTG +EXTERN char e_missing_colon_str[] + INIT(= "E627: Missing colon: %s"); +EXTERN char e_missing_bang_or_slash_in_str[] + INIT(= "E628: Missing ! or / in: %s"); +#ifdef NBDEBUG +EXTERN char e_bad_return_from_nb_do_cmd[] + INIT(= "E629: Bad return from nb_do_cmd"); +#endif +#endif +#ifdef FEAT_JOB_CHANNEL +EXTERN char e_str_write_while_not_connected[] + INIT(= N_("E630: %s(): Write while not connected")); +EXTERN char e_str_write_failed[] + INIT(= N_("E631: %s(): Write failed")); +#endif +#ifdef FEAT_NETBEANS_INTG +EXTERN char e_invalid_buffer_identifier_in_getlength[] + INIT(= "E632: Invalid buffer identifier in getLength"); +EXTERN char e_invalid_buffer_identifier_in_gettext[] + INIT(= "E633: Invalid buffer identifier in getText"); +EXTERN char e_invalid_buffer_identifier_in_remove[] + INIT(= "E634: Invalid buffer identifier in remove"); +EXTERN char e_invalid_buffer_identifier_in_insert[] + INIT(= "E635: Invalid buffer identifier in insert"); +EXTERN char e_invalid_buffer_identifier_in_create[] + INIT(= "E636: Invalid buffer identifier in create"); +EXTERN char e_invalid_buffer_identifier_in_startdocumentlisten[] + INIT(= "E637: Invalid buffer identifier in startDocumentListen"); +EXTERN char e_invalid_buffer_identifier_in_stopdocumentlisten[] + INIT(= "E638: Invalid buffer identifier in stopDocumentListen"); +EXTERN char e_invalid_buffer_identifier_in_settitle[] + INIT(= "E639: Invalid buffer identifier in setTitle"); +EXTERN char e_invalid_buffer_identifier_in_initdone[] + INIT(= "E640: Invalid buffer identifier in initDone"); +EXTERN char e_invalid_buffer_identifier_in_setbuffernumber[] + INIT(= "E641: Invalid buffer identifier in setBufferNumber"); +EXTERN char e_file_str_not_found_in_setbuffernumber[] + INIT(= "E642: File %s not found in setBufferNumber"); +EXTERN char e_invalid_buffer_identifier_in_setfullname[] + INIT(= "E643: Invalid buffer identifier in setFullName"); +EXTERN char e_invalid_buffer_identifier_in_editfile[] + INIT(= "E644: Invalid buffer identifier in editFile"); +EXTERN char e_invalid_buffer_identifier_in_setvisible[] + INIT(= "E645: Invalid buffer identifier in setVisible"); +EXTERN char e_invalid_buffer_identifier_in_setmodified[] + INIT(= "E646: Invalid buffer identifier in setModified"); +EXTERN char e_invalid_buffer_identifier_in_setdot[] + INIT(= "E647: Invalid buffer identifier in setDot"); +EXTERN char e_invalid_buffer_identifier_in_close[] + INIT(= "E648: Invalid buffer identifier in close"); +EXTERN char e_invalid_buffer_identifier_in_close_2[] + INIT(= "E649: Invalid buffer identifier in close"); +EXTERN char e_invalid_buffer_identifier_in_defineannotype[] + INIT(= "E650: Invalid buffer identifier in defineAnnoType"); +EXTERN char e_invalid_buffer_identifier_in_addanno[] + INIT(= "E651: Invalid buffer identifier in addAnno"); +EXTERN char e_invalid_buffer_identifier_in_getanno[] + INIT(= "E652: Invalid buffer identifier in getAnno"); +#endif +// E653 unused +EXTERN char e_missing_delimiter_after_search_pattern_str[] + INIT(= N_("E654: Missing delimiter after search pattern: %s")); +#ifdef FEAT_EVAL +EXTERN char e_too_many_symbolic_links_cycle[] + INIT(= N_("E655: Too many symbolic links (cycle?)")); +#endif +#ifdef FEAT_NETBEANS_INTG + // E656 +EXTERN char e_netbeans_disallows_writes_of_unmodified_buffers[] + INIT(= N_("NetBeans disallows writes of unmodified buffers")); + // E657 +EXTERN char e_partial_writes_disallowed_for_netbeans_buffers[] + INIT(= N_("Partial writes disallowed for NetBeans buffers")); +EXTERN char e_netbeans_connection_lost_for_buffer_nr[] + INIT(= N_("E658: NetBeans connection lost for buffer %d")); +#endif +#ifdef FEAT_PYTHON +EXTERN char e_cannot_invoke_python_recursively[] + INIT(= N_("E659: Cannot invoke Python recursively")); +#endif +#ifdef FEAT_NETBEANS_INTG +EXTERN char e_cannot_open_netbeans_connection_info_file[] + INIT(= "E660: Cannot open NetBeans connection info file"); +#endif +#ifdef FEAT_MULTI_LANG +EXTERN char e_sorry_no_str_help_for_str[] + INIT(= N_("E661: Sorry, no '%s' help for %s")); +#endif +EXTERN char e_at_start_of_changelist[] + INIT(= N_("E662: At start of changelist")); +EXTERN char e_at_end_of_changelist[] + INIT(= N_("E663: At end of changelist")); +EXTERN char e_changelist_is_empty[] + INIT(= N_("E664: Changelist is empty")); +#ifdef FEAT_GUI +EXTERN char e_cannot_start_gui_no_valid_font_found[] + INIT(= N_("E665: Cannot start GUI, no valid font found")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_compiler_not_supported_str[] + INIT(= N_("E666: Compiler not supported: %s")); +#endif +#ifdef HAVE_FSYNC +EXTERN char e_fsync_failed[] + INIT(= N_("E667: Fsync failed")); +#endif +#ifdef FEAT_NETBEANS_INTG +EXTERN char e_wrong_access_mode_for_netbeans_connection_info_file_str[] + INIT(= N_("E668: Wrong access mode for NetBeans connection info file: \"%s\"")); +#endif +EXTERN char e_unprintable_character_in_group_name[] + INIT(= N_("E669: Unprintable character in group name")); +EXTERN char e_mix_of_help_file_encodings_within_language_str[] + INIT(= N_("E670: Mix of help file encodings within a language: %s")); +#ifdef FEAT_GUI_MSWIN +EXTERN char e_cannot_find_window_title_str[] + INIT(= N_("E671: Cannot find window title \"%s\"")); +EXTERN char e_unable_to_open_window_inside_mdi_application[] + INIT(= N_("E672: Unable to open window inside MDI application")); +#endif +#if defined(FEAT_PRINTER) && defined(FEAT_POSTSCRIPT) +EXTERN char e_incompatible_multi_byte_encoding_and_character_set[] + INIT(= N_("E673: Incompatible multi-byte encoding and character set")); +EXTERN char e_printmbcharset_cannot_be_empty_with_multi_byte_encoding[] + INIT(= N_("E674: printmbcharset cannot be empty with multi-byte encoding.")); +EXTERN char e_no_default_font_specified_for_multi_byte_printing[] + INIT(= N_("E675: No default font specified for multi-byte printing.")); +#endif +EXTERN char e_no_matching_autocommands_for_buftype_str_buffer[] + INIT(= N_("E676: No matching autocommands for buftype=%s buffer")); +#ifdef FEAT_SYN_HL +EXTERN char e_error_writing_temp_file[] + INIT(= N_("E677: Error writing temp file")); +#endif +EXTERN char e_invalid_character_after_str_2[] + INIT(= N_("E678: Invalid character after %s%%[dxouU]")); +#ifdef FEAT_SYN_HL +EXTERN char e_recursive_loop_loading_syncolor_vim[] + INIT(= N_("E679: Recursive loop loading syncolor.vim")); +#endif +EXTERN char e_buffer_nr_invalid_buffer_number[] + INIT(= N_("E680: : invalid buffer number")); +#ifdef FEAT_QUICKFIX +EXTERN char e_buffer_is_not_loaded[] + INIT(= N_("E681: Buffer is not loaded")); +EXTERN char e_invalid_search_pattern_or_delimiter[] + INIT(= N_("E682: Invalid search pattern or delimiter")); +EXTERN char e_file_name_missing_or_invalid_pattern[] + INIT(= N_("E683: File name missing or invalid pattern")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_list_index_out_of_range_nr[] + INIT(= N_("E684: List index out of range: %ld")); +#endif +EXTERN char e_internal_error_str[] + INIT(= N_("E685: Internal error: %s")); +#ifdef FEAT_EVAL +EXTERN char e_argument_of_str_must_be_list[] + INIT(= N_("E686: Argument of %s must be a List")); +EXTERN char e_less_targets_than_list_items[] + INIT(= N_("E687: Less targets than List items")); +EXTERN char e_more_targets_than_list_items[] + INIT(= N_("E688: More targets than List items")); +EXTERN char e_can_only_index_list_dictionary_or_blob[] + INIT(= N_("E689: Can only index a List, Dictionary or Blob")); +EXTERN char e_missing_in_after_for[] + INIT(= N_("E690: Missing \"in\" after :for")); +EXTERN char e_can_only_compare_list_with_list[] + INIT(= N_("E691: Can only compare List with List")); +EXTERN char e_invalid_operation_for_list[] + INIT(= N_("E692: Invalid operation for List")); +// E693 unused +EXTERN char e_invalid_operation_for_funcrefs[] + INIT(= N_("E694: Invalid operation for Funcrefs")); +EXTERN char e_cannot_index_a_funcref[] + INIT(= N_("E695: Cannot index a Funcref")); +EXTERN char e_missing_comma_in_list_str[] + INIT(= N_("E696: Missing comma in List: %s")); +EXTERN char e_missing_end_of_list_rsb_str[] + INIT(= N_("E697: Missing end of List ']': %s")); +EXTERN char e_variable_nested_too_deep_for_making_copy[] + INIT(= N_("E698: Variable nested too deep for making a copy")); +EXTERN char e_too_many_arguments[] + INIT(= N_("E699: Too many arguments")); +EXTERN char e_unknown_function_str_2[] + INIT(= N_("E700: Unknown function: %s")); +EXTERN char e_invalid_type_for_len[] + INIT(= N_("E701: Invalid type for len()")); +EXTERN char e_sort_compare_function_failed[] + INIT(= N_("E702: Sort compare function failed")); +EXTERN char e_using_funcref_as_number[] + INIT(= N_("E703: Using a Funcref as a Number")); +EXTERN char e_funcref_variable_name_must_start_with_capital_str[] + INIT(= N_("E704: Funcref variable name must start with a capital: %s")); +EXTERN char e_variable_name_conflicts_with_existing_function_str[] + INIT(= N_("E705: Variable name conflicts with existing function: %s")); +// E706 unused +EXTERN char e_function_name_conflicts_with_variable_str[] + INIT(= N_("E707: Function name conflicts with variable: %s")); +EXTERN char e_slice_must_come_last[] + INIT(= N_("E708: [:] must come last")); +EXTERN char e_slice_requires_list_or_blob_value[] + INIT(= N_("E709: [:] requires a List or Blob value")); +EXTERN char e_list_value_has_more_items_than_targets[] + INIT(= N_("E710: List value has more items than targets")); +EXTERN char e_list_value_does_not_have_enough_items[] + INIT(= N_("E711: List value does not have enough items")); +EXTERN char e_argument_of_str_must_be_list_or_dictionary[] + INIT(= N_("E712: Argument of %s must be a List or Dictionary")); +EXTERN char e_cannot_use_empty_key_for_dictionary[] + INIT(= N_("E713: Cannot use empty key for Dictionary")); +EXTERN char e_list_required[] + INIT(= N_("E714: List required")); +EXTERN char e_dictionary_required[] + INIT(= N_("E715: Dictionary required")); +EXTERN char e_key_not_present_in_dictionary_str[] + INIT(= N_("E716: Key not present in Dictionary: \"%s\"")); +EXTERN char e_dictionary_entry_already_exists[] + INIT(= N_("E717: Dictionary entry already exists")); +EXTERN char e_funcref_required[] + INIT(= N_("E718: Funcref required")); +EXTERN char e_cannot_slice_dictionary[] + INIT(= N_("E719: Cannot slice a Dictionary")); +EXTERN char e_missing_colon_in_dictionary_str[] + INIT(= N_("E720: Missing colon in Dictionary: %s")); +EXTERN char e_duplicate_key_in_dictionary_str[] + INIT(= N_("E721: Duplicate key in Dictionary: \"%s\"")); +EXTERN char e_missing_comma_in_dictionary_str[] + INIT(= N_("E722: Missing comma in Dictionary: %s")); +EXTERN char e_missing_dict_end_str[] + INIT(= N_("E723: Missing end of Dictionary '}': %s")); +EXTERN char e_variable_nested_too_deep_for_displaying[] + INIT(= N_("E724: Variable nested too deep for displaying")); +EXTERN char e_calling_dict_function_without_dictionary_str[] + INIT(= N_("E725: Calling dict function without Dictionary: %s")); +EXTERN char e_stride_is_zero[] + INIT(= N_("E726: Stride is zero")); +EXTERN char e_start_past_end[] + INIT(= N_("E727: Start past end")); +EXTERN char e_using_dictionary_as_number[] + INIT(= N_("E728: Using a Dictionary as a Number")); +EXTERN char e_using_funcref_as_string[] + INIT(= N_("E729: Using a Funcref as a String")); +EXTERN char e_using_list_as_string[] + INIT(= N_("E730: Using a List as a String")); +EXTERN char e_using_dictionary_as_string[] + INIT(= N_("E731: Using a Dictionary as a String")); +EXTERN char e_using_endfor_with_while[] + INIT(= N_("E732: Using :endfor with :while")); +EXTERN char e_using_endwhile_with_for[] + INIT(= N_("E733: Using :endwhile with :for")); +EXTERN char e_wrong_variable_type_for_str_equal[] + INIT(= N_("E734: Wrong variable type for %s=")); +EXTERN char e_can_only_compare_dictionary_with_dictionary[] + INIT(= N_("E735: Can only compare Dictionary with Dictionary")); +EXTERN char e_invalid_operation_for_dictionary[] + INIT(= N_("E736: Invalid operation for Dictionary")); +EXTERN char e_key_already_exists_str[] + INIT(= N_("E737: Key already exists: %s")); +EXTERN char e_cant_list_variables_for_str[] + INIT(= N_("E738: Can't list variables for %s")); +EXTERN char e_cannot_create_directory_str[] + INIT(= N_("E739: Cannot create directory: %s")); +EXTERN char e_too_many_arguments_for_function_str_2[] + INIT(= N_("E740: Too many arguments for function %s")); +EXTERN char e_value_is_locked[] + INIT(= N_("E741: Value is locked")); +EXTERN char e_value_is_locked_str[] + INIT(= N_("E741: Value is locked: %s")); +EXTERN char e_cannot_change_value[] + INIT(= N_("E742: Cannot change value")); +EXTERN char e_cannot_change_value_of_str[] + INIT(= N_("E742: Cannot change value of %s")); +EXTERN char e_variable_nested_too_deep_for_unlock[] + INIT(= N_("E743: Variable nested too deep for (un)lock")); +#endif +#ifdef FEAT_NETBEANS_INTG +EXTERN char e_netbeans_does_not_allow_changes_in_read_only_files[] + INIT(= N_("E744: NetBeans does not allow changes in read-only files")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_using_list_as_number[] + INIT(= N_("E745: Using a List as a Number")); +EXTERN char e_function_name_does_not_match_script_file_name_str[] + INIT(= N_("E746: Function name does not match script file name: %s")); +#endif +EXTERN char e_cannot_change_directory_buffer_is_modified_add_bang_to_override[] + INIT(= N_("E747: Cannot change directory, buffer is modified (add ! to override)")); +EXTERN char e_no_previously_used_register[] + INIT(= N_("E748: No previously used register")); +EXTERN char e_empty_buffer[] + INIT(= N_("E749: Empty buffer")); +#ifdef FEAT_PROFILE +EXTERN char e_first_use_profile_start_fname[] + INIT(= N_("E750: First use \":profile start {fname}\"")); +#endif +#ifdef FEAT_SPELL +EXTERN char e_output_file_name_must_not_have_region_name[] + INIT(= N_("E751: Output file name must not have region name")); +EXTERN char e_no_previous_spell_replacement[] + INIT(= N_("E752: No previous spell replacement")); +EXTERN char e_not_found_str[] + INIT(= N_("E753: Not found: %s")); +EXTERN char e_only_up_to_nr_regions_supported[] + INIT(= N_("E754: Only up to %d regions supported")); +EXTERN char e_invalid_region_in_str[] + INIT(= N_("E755: Invalid region in %s")); +EXTERN char e_spell_checking_is_not_possible[] + INIT(= N_("E756: Spell checking is not possible")); +EXTERN char e_this_does_not_look_like_spell_file[] + INIT(= N_("E757: This does not look like a spell file")); +EXTERN char e_truncated_spell_file[] + INIT(= N_("E758: Truncated spell file")); +EXTERN char e_format_error_in_spell_file[] + INIT(= N_("E759: Format error in spell file")); +EXTERN char e_no_word_count_in_str[] + INIT(= N_("E760: No word count in %s")); +EXTERN char e_format_error_in_affix_file_fol_low_or_upp[] + INIT(= N_("E761: Format error in affix file FOL, LOW or UPP")); +EXTERN char e_character_in_fol_low_or_upp_is_out_of_range[] + INIT(= N_("E762: Character in FOL, LOW or UPP is out of range")); +EXTERN char e_word_characters_differ_between_spell_files[] + INIT(= N_("E763: Word characters differ between spell files")); +#endif +#if defined(FEAT_SYN_HL) || defined(FEAT_COMPL_FUNC) || defined(FEAT_SPELL) +EXTERN char e_option_str_is_not_set[] + INIT(= N_("E764: Option '%s' is not set")); +#endif +#ifdef FEAT_SPELL +EXTERN char e_spellfile_does_not_have_nr_entries[] + INIT(= N_("E765: 'spellfile' does not have %d entries")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_insufficient_arguments_for_printf[] + INIT(= N_("E766: Insufficient arguments for printf()")); +#endif +EXTERN char e_too_many_arguments_to_printf[] + INIT(= N_("E767: Too many arguments for printf()")); +EXTERN char e_swap_file_exists_str_silent_overrides[] + INIT(= N_("E768: Swap file exists: %s (:silent! overrides)")); +EXTERN char e_missing_rsb_after_str_lsb[] + INIT(= N_("E769: Missing ] after %s[")); +#ifdef FEAT_SPELL +EXTERN char e_unsupported_section_in_spell_file[] + INIT(= N_("E770: Unsupported section in spell file")); +EXTERN char e_old_spell_file_needs_to_be_updated[] + INIT(= N_("E771: Old spell file, needs to be updated")); +EXTERN char e_spell_file_is_for_newer_version_of_vim[] + INIT(= N_("E772: Spell file is for newer version of Vim")); +#endif +EXTERN char e_symlink_loop_for_str[] + INIT(= N_("E773: Symlink loop for \"%s\"")); +#ifdef FEAT_EVAL +EXTERN char e_operatorfunc_is_empty[] + INIT(= N_("E774: 'operatorfunc' is empty")); +#else +EXTERN char e_eval_feature_not_available[] + INIT(= N_("E775: Eval feature not available")); +#endif +#ifdef FEAT_QUICKFIX +EXTERN char e_no_location_list[] + INIT(= N_("E776: No location list")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_string_or_list_expected[] + INIT(= N_("E777: String or List expected")); +#endif +#ifdef FEAT_SPELL +EXTERN char e_this_does_not_look_like_sug_file_str[] + INIT(= N_("E778: This does not look like a .sug file: %s")); +EXTERN char e_old_sug_file_needs_to_be_updated_str[] + INIT(= N_("E779: Old .sug file, needs to be updated: %s")); +EXTERN char e_sug_file_is_for_newer_version_of_vim_str[] + INIT(= N_("E780: .sug file is for newer version of Vim: %s")); +EXTERN char e_sug_file_doesnt_match_spl_file_str[] + INIT(= N_("E781: .sug file doesn't match .spl file: %s")); +EXTERN char e_error_while_reading_sug_file_str[] + INIT(= N_("E782: Error while reading .sug file: %s")); +EXTERN char e_duplicate_char_in_map_entry[] + INIT(= N_("E783: Duplicate char in MAP entry")); +#endif +EXTERN char e_cannot_close_last_tab_page[] + INIT(= N_("E784: Cannot close last tab page")); +#ifdef FEAT_EVAL +# ifdef FEAT_COMPL_FUNC +EXTERN char e_complete_can_only_be_used_in_insert_mode[] + INIT(= N_("E785: complete() can only be used in Insert mode")); +# endif +EXTERN char e_range_not_allowed[] + INIT(= N_("E786: Range not allowed")); +#endif +#ifdef FEAT_DIFF +EXTERN char e_buffer_changed_unexpectedly[] + INIT(= N_("E787: Buffer changed unexpectedly")); +#endif +EXTERN char e_not_allowed_to_edit_another_buffer_now[] + INIT(= N_("E788: Not allowed to edit another buffer now")); +#ifdef FEAT_SYN_HL +EXTERN char e_error_missing_rsb_str[] + INIT(= N_("E789: Missing ']': %s")); +#endif +EXTERN char e_undojoin_is_not_allowed_after_undo[] + INIT(= N_("E790: undojoin is not allowed after undo")); +#ifdef FEAT_KEYMAP +EXTERN char e_empty_keymap_entry[] + INIT(= N_("E791: Empty keymap entry")); +#endif +#ifdef FEAT_MENU +EXTERN char e_empty_menu_name[] + INIT(= N_("E792: Empty menu name")); +#endif +#ifdef FEAT_DIFF +EXTERN char e_no_other_buffer_in_diff_mode_is_modifiable[] + INIT(= N_("E793: No other buffer in diff mode is modifiable")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_cannot_set_variable_in_sandbox[] + INIT(= N_("E794: Cannot set variable in the sandbox")); +EXTERN char e_cannot_set_variable_in_sandbox_str[] + INIT(= N_("E794: Cannot set variable in the sandbox: \"%s\"")); +EXTERN char e_cannot_delete_variable[] + INIT(= N_("E795: Cannot delete variable")); +EXTERN char e_cannot_delete_variable_str[] + INIT(= N_("E795: Cannot delete variable %s")); +#endif +#ifdef MSWIN + // E796 +EXTERN char e_writing_to_device_disabled_with_opendevice_option[] + INIT(= N_("writing to device disabled with 'opendevice' option")); +#endif +#ifdef FEAT_SPELL +EXTERN char e_spellfilemising_autocommand_deleted_buffer[] + INIT(= N_("E797: SpellFileMissing autocommand deleted buffer")); +#endif +#ifdef FEAT_SEARCH_EXTRA +EXTERN char e_id_is_reserved_for_match_nr[] + INIT(= N_("E798: ID is reserved for \":match\": %d")); +EXTERN char e_invalid_id_nr_must_be_greater_than_or_equal_to_one_1[] + INIT(= N_("E799: Invalid ID: %d (must be greater than or equal to 1)")); +#endif +#ifndef FEAT_ARABIC +EXTERN char e_arabic_cannot_be_used_not_enabled_at_compile_time[] + INIT(= N_("E800: Arabic cannot be used: Not enabled at compile time\n")); +#endif +#ifdef FEAT_SEARCH_EXTRA +EXTERN char e_id_already_taken_nr[] + INIT(= N_("E801: ID already taken: %d")); +EXTERN char e_invalid_id_nr_must_be_greater_than_or_equal_to_one_2[] + INIT(= N_("E802: Invalid ID: %d (must be greater than or equal to 1)")); +EXTERN char e_id_not_found_nr[] + INIT(= N_("E803: ID not found: %d")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_cannot_use_percent_with_float[] + // xgettext:no-c-format + INIT(= N_("E804: Cannot use '%' with Float")); +#endif +EXTERN char e_using_float_as_number[] + INIT(= N_("E805: Using a Float as a Number")); +EXTERN char e_using_float_as_string[] + INIT(= N_("E806: Using a Float as a String")); +EXTERN char e_expected_float_argument_for_printf[] + INIT(= N_("E807: Expected Float argument for printf()")); +#if defined(FEAT_EVAL) +EXTERN char e_number_or_float_required[] + INIT(= N_("E808: Number or Float required")); +#endif +#ifndef FEAT_EVAL +EXTERN char e_hashsmall_is_not_available_without_the_eval_feature[] + INIT(= N_("E809: #< is not available without the +eval feature")); +#endif +#ifdef FEAT_DIFF +EXTERN char e_cannot_read_or_write_temp_files[] + INIT(= N_("E810: Cannot read or write temp files")); +#endif +EXTERN char e_not_allowed_to_change_buffer_information_now[] + INIT(= N_("E811: Not allowed to change buffer information now")); +EXTERN char e_autocommands_changed_buffer_or_buffer_name[] + INIT(= N_("E812: Autocommands changed buffer or buffer name")); +EXTERN char e_cannot_close_autocmd_or_popup_window[] + INIT(= N_("E813: Cannot close autocmd or popup window")); +EXTERN char e_cannot_close_window_only_autocmd_window_would_remain[] + INIT(= N_("E814: Cannot close window, only autocmd window would remain")); +#ifdef FEAT_MZSCHEME +EXTERN char e_sorry_this_command_is_disabled_the_mzscheme_libraries_could_not_be_loaded[] + INIT(= N_("E815: Sorry, this command is disabled, the MzScheme libraries could not be loaded.")); +#endif +#ifdef FEAT_DIFF +EXTERN char e_cannot_read_patch_output[] + INIT(= N_("E816: Cannot read patch output")); +#endif +#ifdef FEAT_CRYPT +EXTERN char e_blowfish_big_little_endian_use_wrong[] + INIT(= N_("E817: Blowfish big/little endian use wrong")); +EXTERN char e_sha256_test_failed[] + INIT(= N_("E818: sha256 test failed")); +EXTERN char e_blowfish_test_failed[] + INIT(= N_("E819: Blowfish test failed")); +EXTERN char e_sizeof_uint32_isnot_four[] + INIT(= N_("E820: sizeof(uint32_t) != 4")); +EXTERN char e_file_is_encrypted_with_unknown_method[] + INIT(= N_("E821: File is encrypted with unknown method")); +#endif +#ifdef FEAT_PERSISTENT_UNDO +EXTERN char e_cannot_open_undo_file_for_reading_str[] + INIT(= N_("E822: Cannot open undo file for reading: %s")); +EXTERN char e_not_an_undo_file_str[] + INIT(= N_("E823: Not an undo file: %s")); +EXTERN char e_incompatible_undo_file_str[] + INIT(= N_("E824: Incompatible undo file: %s")); +EXTERN char e_corrupted_undo_file_str_str[] + INIT(= N_("E825: Corrupted undo file (%s): %s")); +# ifdef FEAT_CRYPT +EXTERN char e_undo_file_decryption_failed[] + INIT(= N_("E826: Undo file decryption failed: %s")); +# else +EXTERN char e_undo_file_is_encrypted_str[] + INIT(= N_("E827: Undo file is encrypted: %s")); +# endif +EXTERN char e_cannot_open_undo_file_for_writing_str[] + INIT(= N_("E828: Cannot open undo file for writing: %s")); +EXTERN char e_write_error_in_undo_file_str[] + INIT(= N_("E829: Write error in undo file: %s")); +#endif +EXTERN char e_undo_number_nr_not_found[] + INIT(= N_("E830: Undo number %ld not found")); +#ifdef FEAT_CRYPT +EXTERN char e_bf_key_init_called_with_empty_password[] + INIT(= N_("E831: bf_key_init() called with empty password")); +# ifdef FEAT_PERSISTENT_UNDO +EXTERN char e_non_encrypted_file_has_encrypted_undo_file_str[] + INIT(= N_("E832: Non-encrypted file has encrypted undo file: %s")); +# endif +#else +EXTERN char e_str_is_encrypted_and_this_version_of_vim_does_not_support_encryption[] + INIT(= N_("E833: %s is encrypted and this version of Vim does not support encryption")); +#endif +EXTERN char e_conflicts_with_value_of_listchars[] + INIT(= N_("E834: Conflicts with value of 'listchars'")); +EXTERN char e_conflicts_with_value_of_fillchars[] + INIT(= N_("E835: Conflicts with value of 'fillchars'")); +#ifdef DYNAMIC_PYTHON +EXTERN char e_this_vim_cannot_execute_python_after_using_py3[] + INIT(= N_("E836: This Vim cannot execute :python after using :py3")); +EXTERN char e_this_vim_cannot_execute_py3_after_using_python[] + INIT(= N_("E837: This Vim cannot execute :py3 after using :python")); +#endif +#if defined(FEAT_NETBEANS_INTG) && defined(FEAT_GUI) +EXTERN char e_netbeans_is_not_supported_with_this_GUI[] + INIT(= N_("E838: NetBeans is not supported with this GUI")); +#endif +// E839 unused +# ifdef FEAT_COMPL_FUNC +EXTERN char e_complete_function_deleted_text[] + INIT(= N_("E840: Completion function deleted text")); +# endif +EXTERN char e_reserved_name_cannot_be_used_for_user_defined_command[] + INIT(= N_("E841: Reserved name, cannot be used for user defined command")); +EXTERN char e_no_line_number_to_use_for_slnum[] + INIT(= N_("E842: No line number to use for \"\"")); +#ifdef FEAT_CRYPT +EXTERN char e_error_while_updating_swap_file_crypt[] + INIT(= N_("E843: Error while updating swap file crypt")); +#endif +#ifdef FEAT_CONCEAL +EXTERN char e_invalid_cchar_value[] + INIT(= N_("E844: Invalid cchar value")); +#endif +#ifdef FEAT_SPELL +EXTERN char e_insufficient_memory_word_list_will_be_incomplete[] + INIT(= N_("E845: Insufficient memory, word list will be incomplete")); +#endif +EXTERN char e_key_code_not_set[] + INIT(= N_("E846: Key code not set")); +#ifdef FEAT_SYN_HL +EXTERN char e_too_many_syntax_includes[] + INIT(= N_("E847: Too many syntax includes")); +EXTERN char e_too_many_syntax_clusters[] + INIT(= N_("E848: Too many syntax clusters")); +#endif +EXTERN char e_too_many_highlight_and_syntax_groups[] + INIT(= N_("E849: Too many highlight and syntax groups")); +#ifndef FEAT_CLIPBOARD +EXTERN char e_invalid_register_name[] + INIT(= N_("E850: Invalid register name")); +#endif +#ifdef FEAT_GUI +EXTERN char e_failed_to_create_new_process_for_GUI[] + INIT(= N_("E851: Failed to create a new process for the GUI")); +EXTERN char e_the_child_process_failed_to_start_GUI[] + INIT(= N_("E852: The child process failed to start the GUI")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_duplicate_argument_name_str[] + INIT(= N_("E853: Duplicate argument name: %s")); +#endif +EXTERN char e_path_too_long_for_completion[] + INIT(= N_("E854: Path too long for completion")); +EXTERN char e_autocommands_caused_command_to_abort[] + INIT(= N_("E855: Autocommands caused command to abort")); +#ifdef FEAT_EVAL +EXTERN char e_assert_fails_second_arg[] + INIT(= N_("E856: \"assert_fails()\" second argument must be a string or a list with one or two strings")); +EXTERN char e_dictionary_key_str_required[] + INIT(= N_("E857: Dictionary key \"%s\" required")); +#endif +#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) +EXTERN char e_eval_did_not_return_valid_python_object[] + INIT(= N_("E858: Eval did not return a valid python object")); +EXTERN char e_failed_to_convert_returned_python_object_to_vim_value[] + INIT(= N_("E859: Failed to convert returned python object to a Vim value")); +#endif +#ifdef FEAT_PROP_POPUP +EXTERN char e_need_id_and_type_or_types_with_both[] + INIT(= N_("E860: Need 'id' and 'type' or 'types' with 'both'")); +# ifdef FEAT_TERMINAL +EXTERN char e_cannot_open_second_popup_with_terminal[] + INIT(= N_("E861: Cannot open a second popup with a terminal")); +# endif +#endif +#ifdef FEAT_EVAL +EXTERN char e_cannot_use_g_here[] + INIT(= N_("E862: Cannot use g: here")); +#endif +#if defined(FEAT_PROP_POPUP) && defined(FEAT_TERMINAL) +EXTERN char e_not_allowed_for_terminal_in_popup_window[] + INIT(= N_("E863: Not allowed for a terminal in a popup window")); +#endif +EXTERN char e_percent_hash_can_only_be_followed_by_zero_one_two_automatic_engine_will_be_used[] + // xgettext:no-c-format + INIT(= N_("E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be used")); +EXTERN char e_nfa_regexp_end_encountered_prematurely[] + INIT(= N_("E865: (NFA) Regexp end encountered prematurely")); +EXTERN char e_nfa_regexp_misplaced_chr[] + INIT(= N_("E866: (NFA regexp) Misplaced %c")); +EXTERN char e_nfa_regexp_unknown_operator_z_chr[] + INIT(= N_("E867: (NFA regexp) Unknown operator '\\z%c'")); +EXTERN char e_nfa_regexp_unknown_operator_percent_chr[] + INIT(= N_("E867: (NFA regexp) Unknown operator '\\%%%c'")); +EXTERN char e_error_building_nfa_with_equivalence_class[] + INIT(= N_("E868: Error building NFA with equivalence class!")); +EXTERN char e_nfa_regexp_unknown_operator_at_chr[] + INIT(= N_("E869: (NFA regexp) Unknown operator '\\@%c'")); +EXTERN char e_nfa_regexp_error_reading_repetition_limits[] + INIT(= N_("E870: (NFA regexp) Error reading repetition limits")); +EXTERN char e_nfa_regexp_cant_have_multi_follow_multi[] + INIT(= N_("E871: (NFA regexp) Can't have a multi follow a multi")); +EXTERN char e_nfa_regexp_too_many_parens[] + INIT(= N_("E872: (NFA regexp) Too many '('")); +EXTERN char e_nfa_regexp_proper_termination_error[] + INIT(= N_("E873: (NFA regexp) proper termination error")); +EXTERN char e_nfa_regexp_could_not_pop_stack[] + INIT(= N_("E874: (NFA regexp) Could not pop the stack!")); +EXTERN char e_nfa_regexp_while_converting_from_postfix_to_nfa_too_many_stats_left_on_stack[] + INIT(= N_("E875: (NFA regexp) (While converting from postfix to NFA), too many states left on stack")); +EXTERN char e_nfa_regexp_not_enough_space_to_store_whole_nfa[] + INIT(= N_("E876: (NFA regexp) Not enough space to store the whole NFA")); +EXTERN char e_nfa_regexp_invalid_character_class_nr[] + INIT(= N_("E877: (NFA regexp) Invalid character class: %d")); +EXTERN char e_nfa_regexp_could_not_allocate_memory_for_branch_traversal[] + INIT(= N_("E878: (NFA regexp) Could not allocate memory for branch traversal!")); +#ifdef FEAT_SYN_HL +EXTERN char e_nfa_regexp_too_many_z[] + INIT(= N_("E879: (NFA regexp) Too many \\z(")); +#endif +#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) +EXTERN char e_cant_handle_systemexit_of_python_exception_in_vim[] + INIT(= N_("E880: Can't handle SystemExit of python exception in vim")); +#endif +EXTERN char e_line_count_changed_unexpectedly[] + INIT(= N_("E881: Line count changed unexpectedly")); +#ifdef FEAT_EVAL +EXTERN char e_uniq_compare_function_failed[] + INIT(= N_("E882: Uniq compare function failed")); +EXTERN char e_search_pattern_and_expression_register_may_not_contain_two_or_more_lines[] + INIT(= N_("E883: Search pattern and expression register may not contain two or more lines")); +EXTERN char e_function_name_cannot_contain_colon_str[] + INIT(= N_("E884: Function name cannot contain a colon: %s")); +#endif +#ifdef FEAT_SIGNS +EXTERN char e_not_possible_to_change_sign_str[] + INIT(= N_("E885: Not possible to change sign %s")); +#endif +#ifdef FEAT_VIMINFO +EXTERN char e_cant_rename_viminfo_file_to_str[] + INIT(= N_("E886: Can't rename viminfo file to %s!")); +#endif +EXTERN char e_sorry_this_command_is_disabled_python_side_module_could_not_be_loaded[] + INIT(= N_("E887: Sorry, this command is disabled, the Python's site module could not be loaded.")); +EXTERN char e_nfa_regexp_cannot_repeat_str[] + INIT(= N_("E888: (NFA regexp) cannot repeat %s")); +#ifdef FEAT_PROP_POPUP +EXTERN char e_number_required[] + INIT(= N_("E889: Number required")); +#endif +#ifdef FEAT_SYN_HL +EXTERN char e_trailing_char_after_rsb_str_str[] + INIT(= N_("E890: Trailing char after ']': %s]%s")); +#endif +EXTERN char e_using_funcref_as_float[] + INIT(= N_("E891: Using a Funcref as a Float")); +EXTERN char e_using_string_as_float[] + INIT(= N_("E892: Using a String as a Float")); +EXTERN char e_using_list_as_float[] + INIT(= N_("E893: Using a List as a Float")); +EXTERN char e_using_dictionary_as_float[] + INIT(= N_("E894: Using a Dictionary as a Float")); +#ifdef FEAT_MZSCHEME +EXTERN char e_sorry_this_command_is_disabled_the_mzscheme_racket_base_module_could_not_be_loaded[] + INIT(= N_("E895: Sorry, this command is disabled, the MzScheme's racket/base module could not be loaded.")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_argument_of_str_must_be_list_dictionary_or_blob[] + INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob")); +EXTERN char e_list_or_blob_required[] + INIT(= N_("E897: List or Blob required")); +#endif +#ifdef FEAT_JOB_CHANNEL +EXTERN char e_socket_in_channel_connect[] + INIT(= N_("E898: socket() in channel_connect()")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_argument_of_str_must_be_list_or_blob[] + INIT(= N_("E899: Argument of %s must be a List or Blob")); +EXTERN char e_maxdepth_must_be_non_negative_number[] + INIT(= N_("E900: maxdepth must be non-negative number")); +#endif +#ifdef FEAT_JOB_CHANNEL +EXTERN char e_getaddrinfo_in_channel_open_str[] + INIT(= N_("E901: getaddrinfo() in channel_open(): %s")); +# ifndef FEAT_IPV6 +EXTERN char e_gethostbyname_in_channel_open[] + INIT(= N_("E901: gethostbyname() in channel_open()")); +# endif +EXTERN char e_cannot_connect_to_port[] + INIT(= N_("E902: Cannot connect to port")); +EXTERN char e_received_command_with_non_string_argument[] + INIT(= N_("E903: Received command with non-string argument")); +EXTERN char e_last_argument_for_expr_call_must_be_number[] + INIT(= N_("E904: Last argument for expr/call must be a number")); +EXTERN char e_third_argument_for_call_must_be_list[] + INIT(= N_("E904: Third argument for call must be a list")); +EXTERN char e_received_unknown_command_str[] + INIT(= N_("E905: Received unknown command: %s")); +EXTERN char e_not_an_open_channel[] + INIT(= N_("E906: Not an open channel")); +#endif +EXTERN char e_using_special_value_as_float[] + INIT(= N_("E907: Using a special value as a Float")); +#ifdef FEAT_EVAL +EXTERN char e_using_invalid_value_as_string_str[] + INIT(= N_("E908: Using an invalid value as a String: %s")); +EXTERN char e_cannot_index_special_variable[] + INIT(= N_("E909: Cannot index a special variable")); +#endif +#ifdef FEAT_JOB_CHANNEL +EXTERN char e_using_job_as_number[] + INIT(= N_("E910: Using a Job as a Number")); +EXTERN char e_using_job_as_float[] + INIT(= N_("E911: Using a Job as a Float")); +EXTERN char e_cannot_use_evalexpr_sendexpr_with_raw_or_nl_channel[] + INIT(= N_("E912: Cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel")); +EXTERN char e_using_channel_as_number[] + INIT(= N_("E913: Using a Channel as a Number")); +EXTERN char e_using_channel_as_float[] + INIT(= N_("E914: Using a Channel as a Float")); +EXTERN char e_in_io_buffer_requires_in_buf_or_in_name_to_be_set[] + INIT(= N_("E915: in_io buffer requires in_buf or in_name to be set")); +EXTERN char e_not_valid_job[] + INIT(= N_("E916: Not a valid job")); +EXTERN char e_cannot_use_callback_with_str[] + INIT(= N_("E917: Cannot use a callback with %s()")); +EXTERN char e_buffer_must_be_loaded_str[] + INIT(= N_("E918: Buffer must be loaded: %s")); +#endif +EXTERN char e_directory_not_found_in_str_str[] + INIT(= N_("E919: Directory not found in '%s': \"%s\"")); +#ifdef FEAT_JOB_CHANNEL +EXTERN char e_io_file_requires_name_to_be_set[] + INIT(= N_("E920: _io file requires _name to be set")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_invalid_callback_argument[] + INIT(= N_("E921: Invalid callback argument")); +EXTERN char e_expected_dict[] + INIT(= N_("E922: Expected a dict")); +EXTERN char e_second_argument_of_function_must_be_list_or_dict[] + INIT(= N_("E923: Second argument of function() must be a list or a dict")); +#endif +#ifdef FEAT_QUICKFIX +EXTERN char e_current_window_was_closed[] + INIT(= N_("E924: Current window was closed")); +EXTERN char e_current_quickfix_list_was_changed[] + INIT(= N_("E925: Current quickfix list was changed")); +EXTERN char e_current_location_list_was_changed[] + INIT(= N_("E926: Current location list was changed")); +#endif +#ifdef FEAT_EVAL +# ifdef FEAT_QUICKFIX +EXTERN char e_invalid_action_str_1[] + INIT(= N_("E927: Invalid action: '%s'")); +# endif +EXTERN char e_string_required[] + INIT(= N_("E928: String required")); +#endif +#ifdef FEAT_VIMINFO +EXTERN char e_too_many_viminfo_temp_files_like_str[] + INIT(= N_("E929: Too many viminfo temp files, like %s!")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_cannot_use_redir_inside_execute[] + INIT(= N_("E930: Cannot use :redir inside execute()")); +#endif +EXTERN char e_buffer_cannot_be_registered[] + INIT(= N_("E931: Buffer cannot be registered")); +#ifdef FEAT_EVAL +EXTERN char e_closure_function_should_not_be_at_top_level_str[] + INIT(= N_("E932: Closure function should not be at top level: %s")); +EXTERN char e_function_was_deleted_str[] + INIT(= N_("E933: Function was deleted: %s")); +#endif +#ifdef FEAT_SIGNS +EXTERN char e_cannot_jump_to_buffer_that_does_not_have_name[] + INIT(= N_("E934: Cannot jump to a buffer that does not have a name")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_invalid_submatch_number_nr[] + INIT(= N_("E935: Invalid submatch number: %d")); +#endif +EXTERN char e_cannot_delete_current_group[] + INIT(= N_("E936: Cannot delete the current group")); +EXTERN char e_attempt_to_delete_buffer_that_is_in_use_str[] + INIT(= N_("E937: Attempt to delete a buffer that is in use: %s")); +#ifdef FEAT_EVAL +EXTERN char e_duplicate_key_in_json_str[] + INIT(= N_("E938: Duplicate key in JSON: \"%s\"")); +#endif +EXTERN char e_positive_count_required[] + INIT(= N_("E939: Positive count required")); +#ifdef FEAT_EVAL +EXTERN char e_cannot_lock_or_unlock_variable_str[] + INIT(= N_("E940: Cannot lock or unlock variable %s")); +# ifdef FEAT_CLIENTSERVER +EXTERN char e_already_started_server[] + INIT(= N_("E941: Already started a server")); +# else +EXTERN char e_clientserver_feature_not_available[] + INIT(= N_("E942: +clientserver feature not available")); +# endif +#endif +EXTERN char e_command_table_needs_to_be_updated_run_make_cmdidxs[] + INIT(= N_("E943: Command table needs to be updated, run 'make cmdidxs'")); +EXTERN char e_reverse_range_in_character_class[] + INIT(= N_("E944: Reverse range in character class")); +EXTERN char e_range_too_large_in_character_class[] + INIT(= N_("E945: Range too large in character class")); +#ifdef FEAT_TERMINAL +EXTERN char e_cannot_make_terminal_with_running_job_modifiable[] + INIT(= N_("E946: Cannot make a terminal with running job modifiable")); +EXTERN char e_job_still_running_in_buffer_str[] + INIT(= N_("E947: Job still running in buffer \"%s\"")); +EXTERN char e_job_still_running[] + INIT(= N_("E948: Job still running")); +EXTERN char e_job_still_running_add_bang_to_end_the_job[] + INIT(= N_("E948: Job still running (add ! to end the job)")); +#endif +EXTERN char e_file_changed_while_writing[] + INIT(= N_("E949: File changed while writing")); +EXTERN char e_cannot_convert_between_str_and_str[] + INIT(= N_("E950: Cannot convert between %s and %s")); +EXTERN char e_percent_value_too_large[] + // xgettext:no-c-format + INIT(= N_("E951: \\% value too large")); +#if defined(FEAT_EVAL) && defined(FEAT_QUICKFIX) +EXTERN char e_autocommand_caused_recursive_behavior[] + INIT(= N_("E952: Autocommand caused recursive behavior")); +#endif +#ifdef FEAT_TERMINAL +EXTERN char e_file_exists_str[] + INIT(= N_("E953: File exists: %s")); +#endif +#if defined(FEAT_TERMGUICOLORS) && defined(FEAT_VTP) +EXTERN char e_24_bit_colors_are_not_supported_on_this_environment[] + INIT(= N_("E954: 24-bit colors are not supported on this environment")); +#endif +#ifdef FEAT_TERMINAL +EXTERN char e_not_terminal_buffer[] + INIT(= N_("E955: Not a terminal buffer")); +#endif +EXTERN char e_cannot_use_pattern_recursively[] + INIT(= N_("E956: Cannot use pattern recursively")); +#ifdef FEAT_EVAL +EXTERN char e_invalid_window_number[] + INIT(= N_("E957: Invalid window number")); +#endif +#ifdef FEAT_TERMINAL +EXTERN char e_job_already_finished[] + INIT(= N_("E958: Job already finished")); +#endif +#ifdef FEAT_DIFF +EXTERN char e_invalid_diff_format[] + INIT(= N_("E959: Invalid diff format.")); +EXTERN char e_problem_creating_internal_diff[] + INIT(= N_("E960: Problem creating the internal diff")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_no_line_number_to_use_for_sflnum[] + INIT(= N_("E961: No line number to use for \"\"")); +EXTERN char e_invalid_action_str_2[] + INIT(= N_("E962: Invalid action: '%s'")); +EXTERN char e_setting_str_to_value_with_wrong_type[] + INIT(= N_("E963: Setting %s to value with wrong type")); +#endif +#ifdef FEAT_PROP_POPUP +EXTERN char_u e_invalid_column_number_nr[] + INIT(= N_("E964: Invalid column number: %ld")); +EXTERN char e_missing_property_type_name[] + INIT(= N_("E965: Missing property type name")); +#endif +#ifdef FEAT_EVAL +EXTERN char_u e_invalid_line_number_nr[] + INIT(= N_("E966: Invalid line number: %ld")); +#endif +#ifdef FEAT_PROP_POPUP +EXTERN char e_text_property_info_corrupted[] + INIT(= N_("E967: Text property info corrupted")); +EXTERN char e_need_at_least_one_of_id_or_type[] + INIT(= N_("E968: Need at least one of 'id' or 'type'")); +EXTERN char e_property_type_str_already_defined[] + INIT(= N_("E969: Property type %s already defined")); +EXTERN char e_unknown_highlight_group_name_str[] + INIT(= N_("E970: Unknown highlight group name: '%s'")); +EXTERN char e_property_type_str_does_not_exist[] + INIT(= N_("E971: Property type %s does not exist")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_blob_value_does_not_have_right_number_of_bytes[] + INIT(= N_("E972: Blob value does not have the right number of bytes")); +EXTERN char e_blob_literal_should_have_an_even_number_of_hex_characters[] + INIT(= N_("E973: Blob literal should have an even number of hex characters")); +EXTERN char e_using_blob_as_number[] + INIT(= N_("E974: Using a Blob as a Number")); +EXTERN char e_using_blob_as_float[] + INIT(= N_("E975: Using a Blob as a Float")); +EXTERN char e_using_blob_as_string[] + INIT(= N_("E976: Using a Blob as a String")); +EXTERN char e_can_only_compare_blob_with_blob[] + INIT(= N_("E977: Can only compare Blob with Blob")); +EXTERN char e_invalid_operation_for_blob[] + INIT(= N_("E978: Invalid operation for Blob")); +EXTERN char e_blob_index_out_of_range_nr[] + INIT(= N_("E979: Blob index out of range: %ld")); +# ifndef USE_INPUT_BUF +EXTERN char e_lowlevel_input_not_supported[] + INIT(= N_("E980: Lowlevel input not supported")); +# endif +#endif +EXTERN char e_command_not_allowed_in_rvim[] + INIT(= N_("E981: Command not allowed in rvim")); +#if defined(FEAT_TERMINAL) && defined(MSWIN) +EXTERN char e_conpty_is_not_available[] + INIT(= N_("E982: ConPTY is not available")); +#endif +EXTERN char e_duplicate_argument_str[] + INIT(= N_("E983: Duplicate argument: %s")); +EXTERN char e_scriptversion_used_outside_of_sourced_file[] + INIT(= N_("E984: :scriptversion used outside of a sourced file")); +#ifdef FEAT_EVAL +EXTERN char e_dot_equal_not_supported_with_script_version_two[] + INIT(= N_("E985: .= is not supported with script version >= 2")); +EXTERN char e_cannot_modify_tag_stack_within_tagfunc[] + INIT(= N_("E986: Cannot modify the tag stack within tagfunc")); +EXTERN char e_invalid_return_value_from_tagfunc[] + INIT(= N_("E987: Invalid return value from tagfunc")); +#endif +#ifdef GUI_MAY_SPAWN +EXTERN char e_gui_cannot_be_used_cannot_execute_gvim_exe[] + INIT(= N_("E988: GUI cannot be used. Cannot execute gvim.exe.")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_non_default_argument_follows_default_argument[] + INIT(= N_("E989: Non-default argument follows default argument")); +EXTERN char e_missing_end_marker_str[] + INIT(= N_("E990: Missing end marker '%s'")); +EXTERN char e_cannot_use_heredoc_here[] + INIT(= N_("E991: Cannot use =<< here")); +#endif +EXTERN char e_not_allowed_in_modeline_when_modelineexpr_is_off[] + INIT(= N_("E992: Not allowed in a modeline when 'modelineexpr' is off")); +#ifdef FEAT_EVAL +EXTERN char e_window_nr_is_not_popup_window[] + INIT(= N_("E993: Window %d is not a popup window")); +EXTERN char e_not_allowed_in_popup_window[] + INIT(= N_("E994: Not allowed in a popup window")); +EXTERN char e_cannot_modify_existing_variable[] + INIT(= N_("E995: Cannot modify existing variable")); +EXTERN char e_cannot_lock_range[] + INIT(= N_("E996: Cannot lock a range")); +EXTERN char e_cannot_lock_option[] + INIT(= N_("E996: Cannot lock an option")); +EXTERN char e_cannot_lock_list_or_dict[] + INIT(= N_("E996: Cannot lock a list or dict")); +EXTERN char e_cannot_lock_environment_variable[] + INIT(= N_("E996: Cannot lock an environment variable")); +EXTERN char e_cannot_lock_register[] + INIT(= N_("E996: Cannot lock a register")); +#endif +#ifdef FEAT_PROP_POPUP +EXTERN char e_tabpage_not_found_nr[] + INIT(= N_("E997: Tabpage not found: %d")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_reduce_of_an_empty_str_with_no_initial_value[] + INIT(= N_("E998: Reduce of an empty %s with no initial value")); +#endif +EXTERN char e_scriptversion_not_supported_nr[] + INIT(= N_("E999: scriptversion not supported: %d")); +// E1000 unused +#ifdef FEAT_EVAL +EXTERN char e_variable_not_found_str[] + INIT(= N_("E1001: Variable not found: %s")); +EXTERN char e_syntax_error_at_str[] + INIT(= N_("E1002: Syntax error at %s")); +EXTERN char e_missing_return_value[] + INIT(= N_("E1003: Missing return value")); +EXTERN char e_white_space_required_before_and_after_str_at_str[] + INIT(= N_("E1004: White space required before and after '%s' at \"%s\"")); +EXTERN char e_too_many_argument_types[] + INIT(= N_("E1005: Too many argument types")); +EXTERN char e_str_is_used_as_argument[] + INIT(= N_("E1006: %s is used as an argument")); +EXTERN char e_mandatory_argument_after_optional_argument[] + INIT(= N_("E1007: Mandatory argument after optional argument")); +EXTERN char e_missing_type_after_str[] + INIT(= N_("E1008: Missing after %s")); +EXTERN char e_missing_gt_after_type_str[] + INIT(= N_("E1009: Missing > after type: %s")); +EXTERN char e_type_not_recognized_str[] + INIT(= N_("E1010: Type not recognized: %s")); +EXTERN char e_name_too_long_str[] + INIT(= N_("E1011: Name too long: %s")); +EXTERN char e_type_mismatch_expected_str_but_got_str[] + INIT(= N_("E1012: Type mismatch; expected %s but got %s")); +EXTERN char e_type_mismatch_expected_str_but_got_str_in_str[] + INIT(= N_("E1012: Type mismatch; expected %s but got %s in %s")); +EXTERN char e_argument_nr_type_mismatch_expected_str_but_got_str[] + INIT(= N_("E1013: Argument %d: type mismatch, expected %s but got %s")); +EXTERN char e_argument_nr_type_mismatch_expected_str_but_got_str_in_str[] + INIT(= N_("E1013: Argument %d: type mismatch, expected %s but got %s in %s")); +EXTERN char e_invalid_key_str[] + INIT(= N_("E1014: Invalid key: %s")); +EXTERN char e_name_expected_str[] + INIT(= N_("E1015: Name expected: %s")); +EXTERN char e_cannot_declare_a_scope_variable_str[] + INIT(= N_("E1016: Cannot declare a %s variable: %s")); +EXTERN char e_cannot_declare_an_environment_variable_str[] + INIT(= N_("E1016: Cannot declare an environment variable: %s")); +EXTERN char e_variable_already_declared_str[] + INIT(= N_("E1017: Variable already declared: %s")); +EXTERN char e_cannot_assign_to_constant_str[] + INIT(= N_("E1018: Cannot assign to a constant: %s")); +EXTERN char e_can_only_concatenate_to_string[] + INIT(= N_("E1019: Can only concatenate to string")); +EXTERN char e_cannot_use_operator_on_new_variable_str[] + INIT(= N_("E1020: Cannot use an operator on a new variable: %s")); +EXTERN char e_const_requires_a_value[] + INIT(= N_("E1021: Const requires a value")); +EXTERN char e_type_or_initialization_required[] + INIT(= N_("E1022: Type or initialization required")); +EXTERN char e_using_number_as_bool_nr[] + INIT(= N_("E1023: Using a Number as a Bool: %lld")); +EXTERN char e_using_number_as_string[] + INIT(= N_("E1024: Using a Number as a String")); +EXTERN char e_using_rcurly_outside_if_block_scope[] + INIT(= N_("E1025: Using } outside of a block scope")); +#endif +EXTERN char e_missing_rcurly[] + INIT(= N_("E1026: Missing }")); +#ifdef FEAT_EVAL +EXTERN char e_missing_return_statement[] + INIT(= N_("E1027: Missing return statement")); +EXTERN char e_compiling_def_function_failed[] + INIT(= N_("E1028: Compiling :def function failed")); +EXTERN char e_expected_str_but_got_str[] + INIT(= N_("E1029: Expected %s but got %s")); +EXTERN char e_using_string_as_number_str[] + INIT(= N_("E1030: Using a String as a Number: \"%s\"")); +EXTERN char e_cannot_use_void_value[] + INIT(= N_("E1031: Cannot use void value")); +EXTERN char e_missing_catch_or_finally[] + INIT(= N_("E1032: Missing :catch or :finally")); +EXTERN char e_catch_unreachable_after_catch_all[] + INIT(= N_("E1033: Catch unreachable after catch-all")); +EXTERN char e_cannot_use_reserved_name_str[] + INIT(= N_("E1034: Cannot use reserved name %s")); +EXTERN char e_percent_requires_number_arguments[] + // xgettext:no-c-format + INIT(= N_("E1035: % requires number arguments")); +EXTERN char e_char_requires_number_or_float_arguments[] + INIT(= N_("E1036: %c requires number or float arguments")); +EXTERN char e_cannot_use_str_with_str[] + INIT(= N_("E1037: Cannot use \"%s\" with %s")); +EXTERN char e_vim9script_can_only_be_used_in_script[] + INIT(= N_("E1038: \"vim9script\" can only be used in a script")); +EXTERN char e_vim9script_must_be_first_command_in_script[] + INIT(= N_("E1039: \"vim9script\" must be the first command in a script")); +#endif +EXTERN char e_cannot_use_scriptversion_after_vim9script[] + INIT(= N_("E1040: Cannot use :scriptversion after :vim9script")); +#ifdef FEAT_EVAL +EXTERN char e_redefining_script_item_str[] + INIT(= N_("E1041: Redefining script item: \"%s\"")); +EXTERN char e_export_can_only_be_used_in_vim9script[] + INIT(= N_("E1042: Export can only be used in vim9script")); +EXTERN char e_invalid_command_after_export[] + INIT(= N_("E1043: Invalid command after :export")); +EXTERN char e_export_with_invalid_argument[] + INIT(= N_("E1044: Export with invalid argument")); +// E1045 not used +// E1046 not used +EXTERN char e_syntax_error_in_import_str[] + INIT(= N_("E1047: Syntax error in import: %s")); +EXTERN char e_item_not_found_in_script_str[] + INIT(= N_("E1048: Item not found in script: %s")); +EXTERN char e_item_not_exported_in_script_str[] + INIT(= N_("E1049: Item not exported in script: %s")); +#endif +EXTERN char e_colon_required_before_range_str[] + INIT(= N_("E1050: Colon required before a range: %s")); +#ifdef FEAT_EVAL +EXTERN char e_wrong_argument_type_for_plus[] + INIT(= N_("E1051: Wrong argument type for +")); +EXTERN char e_cannot_declare_an_option_str[] + INIT(= N_("E1052: Cannot declare an option: %s")); +EXTERN char e_could_not_import_str[] + INIT(= N_("E1053: Could not import \"%s\"")); +EXTERN char e_variable_already_declared_in_script_str[] + INIT(= N_("E1054: Variable already declared in the script: %s")); +EXTERN char e_missing_name_after_dots[] + INIT(= N_("E1055: Missing name after ...")); +EXTERN char e_expected_type_str[] + INIT(= N_("E1056: Expected a type: %s")); +EXTERN char e_missing_enddef[] + INIT(= N_("E1057: Missing :enddef")); +EXTERN char e_function_nesting_too_deep[] + INIT(= N_("E1058: Function nesting too deep")); +EXTERN char e_no_white_space_allowed_before_colon_str[] + INIT(= N_("E1059: No white space allowed before colon: %s")); +EXTERN char e_expected_dot_after_name_str[] + INIT(= N_("E1060: Expected dot after name: %s")); +EXTERN char e_cannot_find_function_str[] + INIT(= N_("E1061: Cannot find function %s")); +EXTERN char e_cannot_index_number[] + INIT(= N_("E1062: Cannot index a Number")); +EXTERN char e_type_mismatch_for_v_variable[] + INIT(= N_("E1063: Type mismatch for v: variable")); +#endif +EXTERN char e_yank_register_changed_while_using_it[] + INIT(= N_("E1064: Yank register changed while using it")); +EXTERN char e_command_cannot_be_shortened_str[] + INIT(= N_("E1065: Command cannot be shortened: %s")); +#ifdef FEAT_EVAL +EXTERN char e_cannot_declare_a_register_str[] + INIT(= N_("E1066: Cannot declare a register: %s")); +EXTERN char e_separator_mismatch_str[] + INIT(= N_("E1067: Separator mismatch: %s")); +EXTERN char e_no_white_space_allowed_before_str_str[] + INIT(= N_("E1068: No white space allowed before '%s': %s")); +EXTERN char e_white_space_required_after_str_str[] + INIT(= N_("E1069: White space required after '%s': %s")); +EXTERN char e_invalid_string_for_import_str[] + INIT(= N_("E1071: Invalid string for :import: %s")); +EXTERN char e_cannot_compare_str_with_str[] + INIT(= N_("E1072: Cannot compare %s with %s")); +EXTERN char e_name_already_defined_str[] + INIT(= N_("E1073: Name already defined: %s")); +EXTERN char e_no_white_space_allowed_after_dot[] + INIT(= N_("E1074: No white space allowed after dot")); +EXTERN char e_namespace_not_supported_str[] + INIT(= N_("E1075: Namespace not supported: %s")); +// E1076 was deleted +EXTERN char e_missing_argument_type_for_str[] + INIT(= N_("E1077: Missing argument type for %s")); +#endif +EXTERN char e_invalid_command_nested_did_you_mean_plusplus_nested[] + INIT(= N_("E1078: Invalid command \"nested\", did you mean \"++nested\"?")); +#ifdef FEAT_EVAL +EXTERN char e_cannot_declare_variable_on_command_line[] + INIT(= N_("E1079: Cannot declare a variable on the command line")); +EXTERN char e_invalid_assignment[] + INIT(= N_("E1080: Invalid assignment")); +EXTERN char e_cannot_unlet_str[] + INIT(= N_("E1081: Cannot unlet %s")); +#endif +EXTERN char e_command_modifier_without_command[] + INIT(= N_("E1082: Command modifier without command")); +#ifdef FEAT_EVAL +EXTERN char e_missing_backtick[] + INIT(= N_("E1083: Missing backtick")); +EXTERN char e_cannot_delete_vim9_script_function_str[] + INIT(= N_("E1084: Cannot delete Vim9 script function %s")); +EXTERN char e_not_callable_type_str[] + INIT(= N_("E1085: Not a callable type: %s")); +// E1086 unused +EXTERN char e_cannot_use_index_when_declaring_variable[] + INIT(= N_("E1087: Cannot use an index when declaring a variable")); +EXTERN char e_script_cannot_import_itself[] + INIT(= N_("E1088: Script cannot import itself")); +EXTERN char e_unknown_variable_str[] + INIT(= N_("E1089: Unknown variable: %s")); +EXTERN char e_cannot_assign_to_argument_str[] + INIT(= N_("E1090: Cannot assign to argument %s")); +EXTERN char e_function_is_not_compiled_str[] + INIT(= N_("E1091: Function is not compiled: %s")); +EXTERN char e_cannot_nest_redir[] + INIT(= N_("E1092: Cannot nest :redir")); +EXTERN char e_expected_nr_items_but_got_nr[] + INIT(= N_("E1093: Expected %d items but got %d")); +EXTERN char e_import_can_only_be_used_in_script[] + INIT(= N_("E1094: Import can only be used in a script")); +EXTERN char e_unreachable_code_after_return[] + INIT(= N_("E1095: Unreachable code after :return")); +EXTERN char e_returning_value_in_function_without_return_type[] + INIT(= N_("E1096: Returning a value in a function without a return type")); +EXTERN char e_line_incomplete[] + INIT(= N_("E1097: Line incomplete")); +EXTERN char e_string_list_or_blob_required[] + INIT(= N_("E1098: String, List or Blob required")); +EXTERN char e_unknown_error_while_executing_str[] + INIT(= N_("E1099: Unknown error while executing %s")); +EXTERN char e_command_not_supported_in_vim9_script_missing_var_str[] + INIT(= N_("E1100: Command not supported in Vim9 script (missing :var?): %s")); +EXTERN char e_cannot_declare_script_variable_in_function_str[] + INIT(= N_("E1101: Cannot declare a script variable in a function: %s")); +EXTERN char e_lambda_function_not_found_str[] + INIT(= N_("E1102: Lambda function not found: %s")); +EXTERN char e_dictionary_not_set[] + INIT(= N_("E1103: Dictionary not set")); +EXTERN char e_missing_gt[] + INIT(= N_("E1104: Missing >")); +EXTERN char e_cannot_convert_str_to_string[] + INIT(= N_("E1105: Cannot convert %s to string")); +EXTERN char e_one_argument_too_many[] + INIT(= N_("E1106: One argument too many")); +EXTERN char e_nr_arguments_too_many[] + INIT(= N_("E1106: %d arguments too many")); +EXTERN char e_string_list_dict_or_blob_required[] + INIT(= N_("E1107: String, List, Dict or Blob required")); +EXTERN char e_item_not_found_str[] + INIT(= N_("E1108: Item not found: %s")); +EXTERN char e_list_item_nr_is_not_list[] + INIT(= N_("E1109: List item %d is not a List")); +EXTERN char e_list_item_nr_does_not_contain_3_numbers[] + INIT(= N_("E1110: List item %d does not contain 3 numbers")); +EXTERN char e_list_item_nr_range_invalid[] + INIT(= N_("E1111: List item %d range invalid")); +EXTERN char e_list_item_nr_cell_width_invalid[] + INIT(= N_("E1112: List item %d cell width invalid")); +EXTERN char e_overlapping_ranges_for_nr[] + INIT(= N_("E1113: Overlapping ranges for 0x%lx")); +EXTERN char e_only_values_of_0x80_and_higher_supported[] + INIT(= N_("E1114: Only values of 0x80 and higher supported")); +EXTERN char e_assert_fails_fourth_argument[] + INIT(= N_("E1115: \"assert_fails()\" fourth argument must be a number")); +EXTERN char e_assert_fails_fifth_argument[] + INIT(= N_("E1116: \"assert_fails()\" fifth argument must be a string")); +EXTERN char e_cannot_use_bang_with_nested_def[] + INIT(= N_("E1117: Cannot use ! with nested :def")); +EXTERN char e_cannot_change_locked_list[] + INIT(= N_("E1118: Cannot change locked list")); +EXTERN char e_cannot_change_locked_list_item[] + INIT(= N_("E1119: Cannot change locked list item")); +EXTERN char e_cannot_change_dict[] + INIT(= N_("E1120: Cannot change dict")); +EXTERN char e_cannot_change_dict_item[] + INIT(= N_("E1121: Cannot change dict item")); +EXTERN char e_variable_is_locked_str[] + INIT(= N_("E1122: Variable is locked: %s")); +EXTERN char e_missing_comma_before_argument_str[] + INIT(= N_("E1123: Missing comma before argument: %s")); +EXTERN char e_str_cannot_be_used_in_legacy_vim_script[] + INIT(= N_("E1124: \"%s\" cannot be used in legacy Vim script")); +EXTERN char e_final_requires_a_value[] + INIT(= N_("E1125: Final requires a value")); +EXTERN char e_cannot_use_let_in_vim9_script[] + INIT(= N_("E1126: Cannot use :let in Vim9 script")); +EXTERN char e_missing_name_after_dot[] + INIT(= N_("E1127: Missing name after dot")); +EXTERN char e_endblock_without_block[] + INIT(= N_("E1128: } without {")); +EXTERN char e_throw_with_empty_string[] + INIT(= N_("E1129: Throw with empty string")); +EXTERN char e_cannot_add_to_null_list[] + INIT(= N_("E1130: Cannot add to null list")); +EXTERN char e_cannot_add_to_null_blob[] + INIT(= N_("E1131: Cannot add to null blob")); +EXTERN char e_missing_function_argument[] + INIT(= N_("E1132: Missing function argument")); +EXTERN char e_cannot_extend_null_dict[] + INIT(= N_("E1133: Cannot extend a null dict")); +EXTERN char e_cannot_extend_null_list[] + INIT(= N_("E1134: Cannot extend a null list")); +EXTERN char e_using_string_as_bool_str[] + INIT(= N_("E1135: Using a String as a Bool: \"%s\"")); +#endif +EXTERN char e_cmd_mapping_must_end_with_cr_before_second_cmd[] + INIT(= N_("E1136: mapping must end with before second ")); +EXTERN char e_cmd_mapping_must_not_include_str_key[] + INIT(= N_("E1137: mapping must not include %s key")); +#ifdef FEAT_EVAL +EXTERN char e_using_bool_as_number[] + INIT(= N_("E1138: Using a Bool as a Number")); +EXTERN char e_missing_matching_bracket_after_dict_key[] + INIT(= N_("E1139: Missing matching bracket after dict key")); +EXTERN char e_for_argument_must_be_sequence_of_lists[] + INIT(= N_("E1140: :for argument must be a sequence of lists")); +EXTERN char e_indexable_type_required[] + INIT(= N_("E1141: Indexable type required")); +EXTERN char e_calling_test_garbagecollect_now_while_v_testing_is_not_set[] + INIT(= N_("E1142: Calling test_garbagecollect_now() while v:testing is not set")); +EXTERN char e_empty_expression_str[] + INIT(= N_("E1143: Empty expression: \"%s\"")); +EXTERN char e_command_str_not_followed_by_white_space_str[] + INIT(= N_("E1144: Command \"%s\" is not followed by white space: %s")); +EXTERN char e_missing_heredoc_end_marker_str[] + INIT(= N_("E1145: Missing heredoc end marker: %s")); +EXTERN char e_command_not_recognized_str[] + INIT(= N_("E1146: Command not recognized: %s")); +EXTERN char e_list_not_set[] + INIT(= N_("E1147: List not set")); +EXTERN char e_cannot_index_str[] + INIT(= N_("E1148: Cannot index a %s")); +EXTERN char e_script_variable_invalid_after_reload_in_function_str[] + INIT(= N_("E1149: Script variable is invalid after reload in function %s")); +EXTERN char e_script_variable_type_changed[] + INIT(= N_("E1150: Script variable type changed")); +EXTERN char e_mismatched_endfunction[] + INIT(= N_("E1151: Mismatched endfunction")); +EXTERN char e_mismatched_enddef[] + INIT(= N_("E1152: Mismatched enddef")); +EXTERN char e_invalid_operation_for_str[] + INIT(= N_("E1153: Invalid operation for %s")); +EXTERN char e_divide_by_zero[] + INIT(= N_("E1154: Divide by zero")); +#endif +EXTERN char e_cannot_define_autocommands_for_all_events[] + INIT(= N_("E1155: Cannot define autocommands for ALL events")); +EXTERN char e_cannot_change_arglist_recursively[] + INIT(= N_("E1156: Cannot change the argument list recursively")); +#ifdef FEAT_EVAL +EXTERN char e_missing_return_type[] + INIT(= N_("E1157: Missing return type")); +EXTERN char e_cannot_use_flatten_in_vim9_script[] + INIT(= N_("E1158: Cannot use flatten() in Vim9 script, use flattennew()")); +#endif +EXTERN char e_cannot_split_window_when_closing_buffer[] + INIT(= N_("E1159: Cannot split a window when closing the buffer")); +#ifdef FEAT_EVAL +EXTERN char e_cannot_use_default_for_variable_arguments[] + INIT(= N_("E1160: Cannot use a default for variable arguments")); +EXTERN char e_cannot_json_encode_str[] + INIT(= N_("E1161: Cannot json encode a %s")); +EXTERN char e_register_name_must_be_one_char_str[] + INIT(= N_("E1162: Register name must be one character: %s")); +EXTERN char e_variable_nr_type_mismatch_expected_str_but_got_str[] + INIT(= N_("E1163: Variable %d: type mismatch, expected %s but got %s")); +EXTERN char e_variable_nr_type_mismatch_expected_str_but_got_str_in_str[] + INIT(= N_("E1163: Variable %d: type mismatch, expected %s but got %s in %s")); +#endif +EXTERN char e_vim9cmd_must_be_followed_by_command[] + INIT(= N_("E1164: vim9cmd must be followed by a command")); +#ifdef FEAT_EVAL +EXTERN char e_cannot_use_range_with_assignment_str[] + INIT(= N_("E1165: Cannot use a range with an assignment: %s")); +EXTERN char e_cannot_use_range_with_dictionary[] + INIT(= N_("E1166: Cannot use a range with a dictionary")); +EXTERN char e_argument_name_shadows_existing_variable_str[] + INIT(= N_("E1167: Argument name shadows existing variable: %s")); +EXTERN char e_argument_already_declared_in_script_str[] + INIT(= N_("E1168: Argument already declared in the script: %s")); +EXTERN char e_expression_too_recursive_str[] + INIT(= N_("E1169: Expression too recursive: %s")); +EXTERN char e_cannot_use_hash_curly_to_start_comment[] + INIT(= N_("E1170: Cannot use #{ to start a comment")); +EXTERN char e_missing_end_block[] + INIT(= N_("E1171: Missing } after inline function")); +EXTERN char e_cannot_use_default_values_in_lambda[] + INIT(= N_("E1172: Cannot use default values in a lambda")); +EXTERN char e_text_found_after_str_str[] + INIT(= N_("E1173: Text found after %s: %s")); +EXTERN char e_string_required_for_argument_nr[] + INIT(= N_("E1174: String required for argument %d")); +EXTERN char e_non_empty_string_required_for_argument_nr[] + INIT(= N_("E1175: Non-empty string required for argument %d")); +EXTERN char e_misplaced_command_modifier[] + INIT(= N_("E1176: Misplaced command modifier")); +EXTERN char e_for_loop_on_str_not_supported[] + INIT(= N_("E1177: For loop on %s not supported")); +EXTERN char e_cannot_lock_unlock_local_variable[] + INIT(= N_("E1178: Cannot lock or unlock a local variable")); +#endif +#ifdef FEAT_TERMINAL +EXTERN char e_failed_to_extract_pwd_from_str_check_your_shell_config[] + INIT(= N_("E1179: Failed to extract PWD from %s, check your shell's config related to OSC 7")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_variable_arguments_type_must_be_list_str[] + INIT(= N_("E1180: Variable arguments type must be a list: %s")); +EXTERN char e_cannot_use_underscore_here[] + INIT(= N_("E1181: Cannot use an underscore here")); +EXTERN char e_cannot_define_dict_func_in_vim9_script_str[] + INIT(= N_("E1182: Cannot define a dict function in Vim9 script: %s")); +EXTERN char e_cannot_use_range_with_assignment_operator_str[] + INIT(= N_("E1183: Cannot use a range with an assignment operator: %s")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_blob_not_set[] + INIT(= N_("E1184: Blob not set")); +EXTERN char e_missing_redir_end[] + INIT(= N_("E1185: Missing :redir END")); +EXTERN char e_expression_does_not_result_in_value_str[] + INIT(= N_("E1186: Expression does not result in a value: %s")); +#endif +EXTERN char e_failed_to_source_defaults[] + INIT(= N_("E1187: Failed to source defaults.vim")); +#if defined(FEAT_TERMINAL) +EXTERN char e_cannot_open_terminal_from_command_line_window[] + INIT(= N_("E1188: Cannot open a terminal from the command line window")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_cannot_use_legacy_with_command_str[] + INIT(= N_("E1189: Cannot use :legacy with this command: %s")); +EXTERN char e_one_argument_too_few[] + INIT(= N_("E1190: One argument too few")); +EXTERN char e_nr_arguments_too_few[] + INIT(= N_("E1190: %d arguments too few")); +EXTERN char e_call_to_function_that_failed_to_compile_str[] + INIT(= N_("E1191: Call to function that failed to compile: %s")); +EXTERN char e_empty_function_name[] + INIT(= N_("E1192: Empty function name")); +#endif +// libsodium +#ifdef FEAT_CRYPT +# ifndef FEAT_SODIUM +EXTERN char e_libsodium_not_built_in[] + INIT(= N_("E1193: cryptmethod xchacha20 not built into this Vim")); +# else +# if 0 +EXTERN char e_libsodium_cannot_encrypt_header[] + INIT(= N_("E1194: Cannot encrypt header, not enough space")); +EXTERN char e_libsodium_cannot_encrypt_buffer[] + INIT(= N_("E1195: Cannot encrypt buffer, not enough space")); +EXTERN char e_libsodium_cannot_decrypt_header[] + INIT(= N_("E1196: Cannot decrypt header, not enough space")); +# endif +EXTERN char e_libsodium_cannot_allocate_buffer[] + INIT(= N_("E1197: Cannot allocate_buffer for encryption")); +EXTERN char e_libsodium_decryption_failed_header_incomplete[] + INIT(= N_("E1198: Decryption failed: Header incomplete!")); +# if 0 +EXTERN char e_libsodium_cannot_decrypt_buffer[] + INIT(= N_("E1199: Cannot decrypt buffer, not enough space")); +# endif +EXTERN char e_libsodium_decryption_failed[] + INIT(= N_("E1200: Decryption failed!")); +EXTERN char e_libsodium_decryption_failed_premature[] + INIT(= N_("E1201: Decryption failed: pre-mature end of file!")); +# endif +#endif +#ifdef FEAT_EVAL +EXTERN char e_no_white_space_allowed_after_str_str[] + INIT(= N_("E1202: No white space allowed after '%s': %s")); +EXTERN char e_dot_can_only_be_used_on_dictionary_str[] + INIT(= N_("E1203: Dot can only be used on a dictionary: %s")); +#endif +EXTERN char e_regexp_number_after_dot_pos_search_chr[] + INIT(= N_("E1204: No Number allowed after .: '\\%%%c'")); +EXTERN char e_no_white_space_allowed_between_option_and[] + INIT(= N_("E1205: No white space allowed between option and")); +#ifdef FEAT_EVAL +EXTERN char e_dict_required_for_argument_nr[] + INIT(= N_("E1206: Dictionary required for argument %d")); +EXTERN char e_expression_without_effect_str[] + INIT(= N_("E1207: Expression without an effect: %s")); +#endif +EXTERN char e_complete_used_without_allowing_arguments[] + INIT(= N_("E1208: -complete used without allowing arguments")); +#ifdef FEAT_EVAL +EXTERN char e_invalid_value_for_line_number_str[] + INIT(= N_("E1209: Invalid value for a line number: \"%s\"")); +EXTERN char e_number_required_for_argument_nr[] + INIT(= N_("E1210: Number required for argument %d")); +EXTERN char e_list_required_for_argument_nr[] + INIT(= N_("E1211: List required for argument %d")); +EXTERN char e_bool_required_for_argument_nr[] + INIT(= N_("E1212: Bool required for argument %d")); +EXTERN char e_redefining_imported_item_str[] + INIT(= N_("E1213: Redefining imported item \"%s\"")); +#endif +#if defined(FEAT_DIGRAPHS) +EXTERN char e_digraph_must_be_just_two_characters_str[] + INIT(= N_("E1214: Digraph must be just two characters: %s")); +EXTERN char e_digraph_argument_must_be_one_character_str[] + INIT(= N_("E1215: Digraph must be one character: %s")); +EXTERN char e_digraph_setlist_argument_must_be_list_of_lists_with_two_items[] + INIT(= N_("E1216: digraph_setlist() argument must be a list of lists with two items")); +#endif +#ifdef FEAT_EVAL +# ifdef FEAT_JOB_CHANNEL +EXTERN char e_chan_or_job_required_for_argument_nr[] + INIT(= N_("E1217: Channel or Job required for argument %d")); +EXTERN char e_job_required_for_argument_nr[] + INIT(= N_("E1218: Job required for argument %d")); +# endif +EXTERN char e_float_or_number_required_for_argument_nr[] + INIT(= N_("E1219: Float or Number required for argument %d")); +EXTERN char e_string_or_number_required_for_argument_nr[] + INIT(= N_("E1220: String or Number required for argument %d")); +# ifdef FEAT_JOB_CHANNEL +EXTERN char e_string_or_blob_required_for_argument_nr[] + INIT(= N_("E1221: String or Blob required for argument %d")); +# endif +EXTERN char e_string_or_list_required_for_argument_nr[] + INIT(= N_("E1222: String or List required for argument %d")); +EXTERN char e_string_or_dict_required_for_argument_nr[] + INIT(= N_("E1223: String or Dictionary required for argument %d")); +EXTERN char e_string_number_or_list_required_for_argument_nr[] + INIT(= N_("E1224: String, Number or List required for argument %d")); +EXTERN char e_string_list_or_dict_required_for_argument_nr[] + INIT(= N_("E1225: String, List or Dictionary required for argument %d")); +EXTERN char e_list_or_blob_required_for_argument_nr[] + INIT(= N_("E1226: List or Blob required for argument %d")); +EXTERN char e_list_or_dict_required_for_argument_nr[] + INIT(= N_("E1227: List or Dictionary required for argument %d")); +EXTERN char e_list_dict_or_blob_required_for_argument_nr[] + INIT(= N_("E1228: List, Dictionary or Blob required for argument %d")); +EXTERN char e_expected_dictionary_for_using_key_str_but_got_str[] + INIT(= N_("E1229: Expected dictionary for using key \"%s\", but got %s")); +#endif +#ifdef FEAT_SODIUM +EXTERN char e_encryption_sodium_mlock_failed[] + INIT(= N_("E1230: Encryption: sodium_mlock() failed")); +#endif +EXTERN char e_cannot_use_bar_to_separate_commands_here_str[] + INIT(= N_("E1231: Cannot use a bar to separate commands here: %s")); +#ifdef FEAT_EVAL +EXTERN char e_argument_of_exists_compiled_must_be_literal_string[] + INIT(= N_("E1232: Argument of exists_compiled() must be a literal string")); +EXTERN char e_exists_compiled_can_only_be_used_in_def_function[] + INIT(= N_("E1233: exists_compiled() can only be used in a :def function")); +#endif +EXTERN char e_legacy_must_be_followed_by_command[] + INIT(= N_("E1234: legacy must be followed by a command")); +#ifdef FEAT_EVAL +// E1235 unused +EXTERN char e_cannot_use_str_itself_it_is_imported[] + INIT(= N_("E1236: Cannot use %s itself, it is imported")); +#endif +EXTERN char e_no_such_user_defined_command_in_current_buffer_str[] + INIT(= N_("E1237: No such user-defined command in current buffer: %s")); +#ifdef FEAT_EVAL +EXTERN char e_blob_required_for_argument_nr[] + INIT(= N_("E1238: Blob required for argument %d")); +EXTERN char e_invalid_value_for_blob_nr[] + INIT(= N_("E1239: Invalid value for blob: %d")); +#endif +EXTERN char e_resulting_text_too_long[] + INIT(= N_("E1240: Resulting text too long")); +#ifdef FEAT_EVAL +EXTERN char e_separator_not_supported_str[] + INIT(= N_("E1241: Separator not supported: %s")); +EXTERN char e_no_white_space_allowed_before_separator_str[] + INIT(= N_("E1242: No white space allowed before separator: %s")); +#endif +#ifdef FEAT_GUI_GTK +EXTERN char e_ascii_code_not_in_range[] + INIT(= N_("E1243: ASCII code not in 32-127 range")); +#endif +#ifdef FEAT_EVAL +# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) +EXTERN char e_bad_color_string_str[] + INIT(= N_("E1244: Bad color string: %s")); +# endif +EXTERN char e_cannot_expand_sfile_in_vim9_function[] + INIT(= N_("E1245: Cannot expand in a Vim9 function")); +EXTERN char e_cannot_find_variable_to_unlock_str[] + INIT(= N_("E1246: Cannot find variable to (un)lock: %s")); +#endif +EXTERN char e_line_number_out_of_range[] + INIT(= N_("E1247: Line number out of range")); +#ifdef FEAT_EVAL +EXTERN char e_closure_called_from_invalid_context[] + INIT(= N_("E1248: Closure called from invalid context")); +#endif +EXTERN char e_highlight_group_name_too_long[] + INIT(= N_("E1249: Highlight group name too long")); +#ifdef FEAT_EVAL +EXTERN char e_argument_of_str_must_be_list_string_dictionary_or_blob[] + INIT(= N_("E1250: Argument of %s must be a List, String, Dictionary or Blob")); +EXTERN char e_list_dict_blob_or_string_required_for_argument_nr[] + INIT(= N_("E1251: List, Dictionary, Blob or String required for argument %d")); +EXTERN char e_string_list_or_blob_required_for_argument_nr[] + INIT(= N_("E1252: String, List or Blob required for argument %d")); +EXTERN char e_string_expected_for_argument_nr[] + INIT(= N_("E1253: String expected for argument %d")); +EXTERN char e_cannot_use_script_variable_in_for_loop[] + INIT(= N_("E1254: Cannot use script variable in for loop")); +#endif +EXTERN char e_cmd_mapping_must_end_with_cr[] + INIT(= N_("E1255: mapping must end with ")); +#ifdef FEAT_EVAL +EXTERN char e_string_or_function_required_for_argument_nr[] + INIT(= N_("E1256: String or function required for argument %d")); +EXTERN char e_imported_script_must_use_as_or_end_in_dot_vim_str[] + INIT(= N_("E1257: Imported script must use \"as\" or end in .vim: %s")); +EXTERN char e_no_dot_after_imported_name_str[] + INIT(= N_("E1258: No '.' after imported name: %s")); +EXTERN char e_missing_name_after_imported_name_str[] + INIT(= N_("E1259: Missing name after imported name: %s")); +EXTERN char e_cannot_unlet_imported_item_str[] + INIT(= N_("E1260: Cannot unlet an imported item: %s")); +EXTERN char e_cannot_import_dot_vim_without_using_as[] + INIT(= N_("E1261: Cannot import .vim without using \"as\"")); +EXTERN char e_cannot_import_same_script_twice_str[] + INIT(= N_("E1262: Cannot import the same script twice: %s")); +EXTERN char e_cannot_use_name_with_hash_in_vim9_script_use_export_instead[] + INIT(= N_("E1263: Cannot use name with # in Vim9 script, use export instead")); +EXTERN char e_autoload_import_cannot_use_absolute_or_relative_path[] + INIT(= N_("E1264: Autoload import cannot use absolute or relative path: %s")); +EXTERN char e_cannot_use_partial_here[] + INIT(= N_("E1265: Cannot use a partial here")); +#endif +#if defined(FEAT_PYTHON3) && defined(MSWIN) +EXTERN char e_critical_error_in_python3_initialization_check_your_installation[] + INIT(= N_("E1266: Critical error in python3 initialization, check your python3 installation")); +#endif +#ifdef FEAT_EVAL +EXTERN char e_function_name_must_start_with_capital_str[] + INIT(= N_("E1267: Function name must start with a capital: %s")); +EXTERN char e_cannot_use_s_colon_in_vim9_script_str[] + INIT(= N_("E1268: Cannot use s: in Vim9 script: %s")); +EXTERN char e_cannot_create_vim9_script_variable_in_function_str[] + INIT(= N_("E1269: Cannot create a Vim9 script variable in a function: %s")); +#endif +EXTERN char e_cannot_use_s_backslash_in_vim9_script[] + INIT(= N_("E1270: Cannot use :s\\/sub/ in Vim9 script")); +#ifdef FEAT_EVAL +EXTERN char e_compiling_closure_without_context_str[] + INIT(= N_("E1271: Compiling closure without context: %s")); +EXTERN char e_using_type_not_in_script_context_str[] + INIT(= N_("E1272: Using type not in a script context: %s")); +#endif +EXTERN char e_nfa_regexp_missing_value_in_chr[] + INIT(= N_("E1273: (NFA regexp) missing value in '\\%%%c'")); +EXTERN char e_no_script_file_name_to_substitute_for_script[] + INIT(= N_("E1274: No script file name to substitute for \"